2017-06-29 4 views
-4

Ich teste eine Java-Abfrage auf unterschiedliche Größe Datensatz, 100 Millionen bis 1 Milliarde Kanten (10 Kanten pro Vertex). Die Abfrage gibt nicht viele Daten zurück, 10 bis 20 Scheitelpunkte mit entsprechenden Kanten, aber es muss das gesamte Dataset gescannt werden.neo4j java Abfrage sehr langsam mit DB> 32G

Ich kann eine große Leistungseinbuße sehen, wenn die Datenbankgröße größer als 32 Gigs ist. änderte ich die Java-Heap-Größe zu 96G und mit den Garbage Collector Optionen gespielt (behalten -XX: + UseG1GC als die Verbesserung der Option) ein besseres Ergebnis zu erhalten, aber ich immer noch ein großes Bad in Leistungen erhalten:

100M Rand Datenbank ist 7.5G: Abfrage dauert 12 min 250M Rand, Datenbank ist 19G: 35 min 500M Rand, Datenbank ist 38G: 12 Stunden mit -XX: + UseG1GC 1B Rand, Datenbank ist 76G: 51 Stunden ohne -XX: + UseG1GC

Weiter für den 500 Millionen und 1 Milliarde Test kann ich sehen, dass der Großteil der Operationen System Operationen 60% gegenüber Benutzer Betrieb 40% sind (von Top Linux Befehl). Wenn ich den kleineren Test ausführe, handelt es sich zu 100% um Benutzervorgänge.

Sind die Java-GC-Verbesserungen in der Enterprise-Edition von Neo4j signifikant genug, um die Leistung der größeren Dataset-Abfrage im gleichen Verhältnis wie die kleinere zu bringen? Gibt es noch etwas, was ich tun kann, um die Leistung größerer Dataset-Abfragen zu verbessern?

tks

ich auf einem 32 Kern 244 RAM virtuellen Server alle diese Tests laufen.

Ich versuchte auch, die Seitencache-Größe zu erhöhen, aber ich sah keine Verbesserung.

Anwendungsfall: Ich suche nach einem Muster in den Daten, die Abfrage scannt den gesamten Datensatz, um 4 oder 5 Knoten zu finden, die ein spezielles Beziehungsmuster haben.

Die Abfrage in Threads ausgeführt, so dass alle 32 Kern gleichzeitig ausgeführt werden.

Ich habe versucht, zu ändern: - Heap Größe - - Cache-Größe - GC Optionen

Aber nicht viel Verbesserung pro Thread Anzahl der Knoten. Ist das eine Java-Einschränkung? danke

+2

Zeigen Sie Ihre Datenmodell und Anwendungsfälle und einige Beispiel-Code. Ansonsten gibt es nicht genug Informationen. – cybersam

+0

stimme w/cybersam zu. Entspricht die Hardware auch der Datensatzgröße? –

+0

Siehe EXPLAIN, PROFILE, um Ihre Abfragen zu optimieren (oder bei Bedarf Indizes zu erstellen) –

Antwort

0

Ich sehe, dass Sie versuchen, den JVM-Heap zu konfigurieren, aber haben Sie die gleiche Sache auf der page cache getan?

Der JVM-Heap wird verwendet, um alle Transaktionsdaten und den Seitencache zu speichern, um die Diagrammdaten im Speicher zu speichern, um Festplatten-E/A zu vermeiden.

Ich schlage vor, Sie zu dieser Dokumentation einen Blick zu nehmen (wenn es nicht bereits getan hat) Seite: https://neo4j.com/docs/operations-manual/3.2/performance/#memory-tuning

einen Java Heap höher haben als 12Go zu einigen großen GCs führen kann und so weniger performant zu sein.

Es gibt einige Verbesserungen in EE, aber für Ihren speziellen Fall denke ich nicht, dass die Lücke signifikant sein wird.

Schließlich, eine Abfrage, die alle Daten benötigt, ist eine schlechte Idee auf jedem Datenbanksystem. Ich bin neugierig auf den Anwendungsfall. kannst du es erklären ?

Wie @ Jerome sagte, müssen Sie Ihre Abfrage optimieren.

Prost.

0

Ich glaube nicht, dass die Optimierung der Abfrage das Problem der Skalierbarkeit erklärt, da die Abfrage in kleineren Datenmengen sehr effizient ist (bis zu 250 Millionen Relationen) und exponentiell langsam, wenn sie größer wird. Java-Speicherverwaltung muss eine Rolle spielen, aber ich kann keinen Weg finden, um es zu umgehen.

Die Abfrage sucht nach Dreieck mit zunehmender Geschwindigkeit, und die maximale und minimale Geschwindigkeit muss innerhalb einer Marge (50) sein. Die Grafik ist vereinfacht, um nur einen Parameter für die Relation (Geschwindigkeit) zu haben. Cypher-Abfrage: Übereinstimmung (a) - [d] -> (b) - [e] -> (c) - [f] -> (a) wo d.Speed ​​< = e.Speed ​​AND e.Speed ​​< = f.geschwindigkeit AND (f.geschwindigkeit-d.geschwindigkeit) < = 50 zurück a, b, c.

Java Abfrage auf jedem Knoten in Threads ausgeführt:

void findTriangleV1(Node n){ 
    Iterable<Relationship> Level1 = n.getRelationships(Direction.OUTGOING); 
    for(Relationship r1 : Level1) { 
     if (r1.getEndNodeId() != n.getId()){ 
      Integer tsr1 = (Integer)r1.getProperty("speed"); 
      Iterable<Relationship> Level2 = r1.getEndNode().getRelationships(Direction.OUTGOING); 
      for(Relationship r2 : Level2) { 
       if (r1.getEndNodeId() != r2.getEndNodeId()){ 
        Integer tsr2 = (Integer)r2.getProperty("speed");         
        if ((tsr2 >= tsr1) && (tsr2 - tsr1 <= limit)){ 
         Iterable<Relationship> Level3 = r2.getEndNode().getRelationships(Direction.OUTGOING); 
         for(Relationship r3 : Level3) { 
          if (r3.getEndNodeId() == n.getId()){ 
           Integer tsr3 = (Integer)r3.getProperty("speed"); 
           if ((tsr3 >= tsr2) && (tsr3 - tsr1 <= limit)){ 
            System.out.print("\nV1 FOUND ONE ["+ n.getId() +" - "+ r1.getEndNodeId()+" - "+ r2.getEndNodeId()+"] & ");  
            System.out.print("speed ["+ tsr1 +" - "+ tsr2+" - "+ tsr3+"] \n"); 
           }        
          } 
         } 
        }     
       } 
      } 
     } 
    } 
    return; 
}