Was ist in MySQL der effektivste Abfrageentwurf für die Verknüpfung großer Tabellen mit vielen bis vielen Beziehungen zwischen den Join-Prädikaten?

9

In unserer Anwendung sammeln wir Daten über die Motorleistung von Automobilen - im Wesentlichen liefern wir Daten über die Motorleistung basierend auf dem Motortyp, dem Fahrzeug, in dem er läuft, und dem Motordesign. Derzeit ist die Basis für neue Reiheneinsätze eine Motor-Ein-Aus-Periode; Wir überwachen Performance-Variablen basierend auf einer Änderung des Engine-Status von aktiv nach inaktiv und umgekehrt. Die verwandte Tabelle engineState sieht folgendermaßen aus:

%Vor%

Für eine spezifische Analyse möchten wir den Tabelleninhalt basierend auf einer Zeilengranularität von Minuten und nicht auf der aktuellen Basis des aktiven / inaktiven Maschinenstatus analysieren. Dazu überlegen wir, eine einfache productionMinute -Tabelle mit einer Zeile für jede Minute in dem Zeitraum zu erstellen, in dem wir analysieren und die Tabellen productionMinute und engineEvent in den Datums- und Uhrzeitspalten jeder Tabelle einfügen. Wenn unser Analysezeitraum vom 2009-12-01 bis 2010-02-28 ist, würden wir eine neue Tabelle mit 129.600 Zeilen erstellen, eine für jede Minute eines jeden Tages für diesen Dreimonatszeitraum. Die ersten paar Zeilen der Tabelle productionMinute :

%Vor%

Der Join zwischen den Tabellen wäre:

%Vor%

Dieser Beitritt bringt jedoch mehrere Umweltprobleme mit sich:

  1. Die Tabelle engineState hat 5 Millionen Zeilen und die Tabelle productionMinute hat 130.000 Zeilen
  2. Wenn sich eine engineState -Zeile mehr als eine Minute erstreckt (dh die Differenz zwischen es.state_start_time und es.state_end_time ist länger als eine Minute), wie im obigen Beispiel, gibt es mehrere productionMinute -Tabellenzeilen Diese Join zu einer einzelnen engineState Tabellenzeile
  3. Wenn mehr als eine Engine in einer bestimmten Minute in Betrieb ist, werden mehrere engineState -Tabellenzeilen zu einer einzelnen productionMinute -Zeile
  4. hinzugefügt

Beim Testen unserer Logik und der Verwendung nur eines kleinen Tabellenextrakts (ein Tag anstatt drei Monate für die Tabelle productionMinute ) dauert die Generierung der Abfrage über eine Stunde. Bei der Untersuchung dieses Artikels, um die Leistung zu verbessern, so dass es möglich wäre, dreimonatige Daten abzufragen, wollten wir eine temporäre Tabelle aus engineEvent eins erstellen, wobei alle Tabellendaten entfernt wurden, die für die Analyse nicht kritisch sind Verbinden der temporären Tabelle mit der Tabelle productionMinute . Wir planen auch mit verschiedenen Joins zu experimentieren - speziell mit einem inneren Join - um zu sehen, ob das die Performance verbessern würde.

Was ist der beste Abfrageentwurf für Join-Tabellen mit der Viele-Viele-Beziehung zwischen den Join-Prädikaten, wie oben beschrieben? Was ist der beste Verbindungstyp (links / rechts, innen)?

    
lighthouse65 13.03.2010, 19:27
quelle

6 Antworten

1

Die Datenwiederherstellungsleistung ist die Funktion von

  • Geschwindigkeit des Zugriffs auf die Daten auf der Festplatte (abhängig auf der Existenz von Indizes, Größe von Tabellen, Cache-Größe, rohe E / A-Geschwindigkeit)
  • Anzahl der Datensätze, die sein müssen zurückgegeben (einige Joins reduzieren die Anzahl der zurückgegebenen Zeilen, einige erhöhen, können einige Bedingungen sein Auf Indizes angewendet, auf die einige zugreifen müssen die Aufzeichnungen)
  • Anzahl der Spalten, die Sie müssen
  • zurückgeben

Für alle diese können Sie optimieren

  • Hinzufügen von Indizes
  • Reduzieren Sie die Größe der Tabelle, indem Sie sie vertikal partitionieren (indem Sie die Tabelle in zwei oder mehr semantisch verschiedene Tabellen aufteilen - zum Beispiel wenn Sie von Ihrer 5m Tabelle nur mit 100k Datensätzen arbeiten 99.5% der Zeit vielleicht Tabellen teilen können) aktiv / inaktiv oder ähnlich)
  • vorausgesetzt, Sie können nicht vertikal teilen Sie könnten eine Tabelle horizontal aufteilen - Anzahl der Spalten, die die Tabelle auch die Abrufgeschwindigkeit beeinflusst (aber nicht so viel)
  • Schließlich kann die rohe E / A-Geschwindigkeit verbessert werden, indem Sie die Tabelle transparent auf mehrere Festplatten aufteilen (aber die zugrunde liegenden Dateisystemeigenschaften kennen)

Indizes haben den größten Einfluss auf die Performance, da sie die Speicherzugriffszeit und -geschwindigkeit im Speicher um Größenordnungen reduzieren können (sie schalten O (n) auf Kosten der Indexstrukturpflege auf O (n)) Sie verlangsamen Updates)

Für eine maximale Suchgeschwindigkeit sollten Indizes alle Joins abdecken und Bedingungen und Abfragen sollten so geschrieben werden, dass der Abfrageoptimierer bestimmen kann, welche davon den höchsten Nutzen bringt, wenn er zuerst ausgeführt wird (höchste Selektivität).

Versuchen Sie für Ihr spezielles Beispiel, verschiedene Kombinationen von Indizes zu vergleichen

  1. pm.production_minute sollte sicher indiziert werden
  2. mit es.state_start_time und es.state_end_time haben Sie 4 mögliche Indexoptionen (die Sie kombinieren können):
    Index auf es.state_start_time
    Index auf es.state_end_time
    Index auf (es.state_start_time, es.state_end_time)
    Index auf (es.state_end_time, es.state_start_time)

Wenn Sie Ihre Daten kennen, können Sie bestimmen, welche optimal ist. Ich wäre nicht überrascht, wenn Sie feststellen würden, dass die letzten zwei Spaltenindizes die besten Ergebnisse bringen würden. Oder mit einer einzelnen Spalte und einem anderen zwei Spaltenindex (aber in umgekehrter Reihenfolge der Spalten).

In beiden Fällen würde der anständige Optimierer in der Lage sein, die Ergebnismenge zu ermitteln, indem er nur die Indizes liest und nicht einmal auf die tatsächlichen Datensätze schaut, was den Festplattenzugriff erheblich einschränkt.

    
Unreason 23.03.2010 13:11
quelle
1

Ich stimme mit vy32 überein. Sie müssen diese Abfrage einmal und nur einmal ausführen, um Ihre Daten in einem für die Analyse geeigneten Format zu erhalten. Sie sollten ein geeignetes ETL-Tool verwenden (oder einfach nur perl oder etwas Einfaches), um die Daten aus der engineState-Tabelle zu ermitteln, die Produktionsminuten zu berechnen und sie dann in eine andere DB zu laden, die für Analyseanfragen geeignet modelliert wurde.

Wenn Sie glauben, dass Ihr Problem durch Sie besteht, denentieren Sie einfach Ihre Daten und weisen Sie winzige Zahlen als Ersatzschlüssel zu. Dies ist ein relativ einfaches (und häufiges) ETL-Problem, das im direkten SQL nicht performant ist, aber mit anderen Sprachen und Tools einfach ist.

Ihr Produktionsvolumen würde von einem echten ETL-Prozess leicht verarbeitet werden.

    
bot403 29.03.2010 17:05
quelle
0

Die Leistung hängt davon ab, wie Ihre Daten in den Tabellen strukturiert sind.

Ein linker oder rechter äußerer Join ist nur nützlich, wenn Sie alle Werte in der linken oder rechten Tabelle für die ausgewählte Projektion haben möchten und diese Werte möglicherweise nicht in der Tabelle enthalten sind, mit der sie verbunden ist.

Vertraue deinem Abfrageoptimierer, um den effizientesten Joinalgorithmus für deine Daten zu finden ... er wurde erstellt, um zu wissen, wie man seine Aufgabe gut macht. Wenn Sie Leistungsprobleme haben, schauen Sie sich an, wie die Daten strukturiert und gespeichert sind.

    
joejoeson 13.03.2010 21:13
quelle
0

Meine Erfahrung ist, dass der MySQL-Abfrageoptimierer ziemlich schlecht ist. Die in PostgreSQL ist viel besser.

Ihr Problem besteht darin, dass Ihre Daten so strukturiert sind, dass sie leichter aufgezeichnet werden können und nicht für eine einfachere Analyse. Mein Vorschlag ist, dass Sie den temporären Tisch erstellen, aber nicht so, wie Sie es sich vorstellen können. Ich denke, dass es am besten ist, am Ende jeden Tages einen Nachbearbeitungsschritt zu haben, der alle Daten des Tages aufnimmt und minutengenaue Einträge in eine neue Tabelle (idealerweise auf einer anderen Spindel) mit einem production_minute-Index erstellt. Diese neue Datenbank ist schneller für analytische Abfragen und die Abfragen verlangsamen die Datenerfassung nicht merklich.

    
vy32 26.03.2010 04:35
quelle
0

Wenn ich richtig verstanden habe, dann sehen Sie sich ein BI-Problem an. Ein BI-Layout würde die operativen Daten abgesehen von der konsolidierten haben.

Damit dies geschieht (schnell und schmutzig), benötigen Sie drei Elemente.

  • Ihre operativen Daten
  • Ein ETL-Job, der nur die von Ihnen angezeigte Abfrage ausführen und das Resultset in eine andere denormalisierte Tabelle einfügen muss
  • Denormalisierte Tabellen, in denen Sie Ihre gesammelten Daten speichern.

Auf diese Weise beschleunigen Sie Ihre Abfrage, da es jetzt eine einfache Auswahl wäre.

Wie in jeder BI-Lösung müssen Sie die ETL täglich (abhängig von Ihren Geschäftsanforderungen) ausführen, um Ihre denormalisierten Informationen zu aktualisieren.

Auf der anderen Seite könnten Sie den BI-Weg ablehnen und an Ihrem aktuellen Schema / Ihrer Anfrage arbeiten. Sie könnten Indizes, Statistiken und Altertabellen hinzufügen, aber meiner Meinung nach ist das keine skalierbare Lösung. Sie könnten das Leistungsproblem für eine drei Monate alte Datenbank lösen, aber was ist, wenn Sie eine drei Jahre alte Datenbank haben?

    
mcabral 30.03.2010 15:52
quelle
0

Die Verwendung von LEFT JOIN, INNER JOIN oder RIGHT JOIN ist ein semantischer Unterschied - die Verwendung einer anderen Verknüpfung für Leistung ist nicht nur eine schlechte Idee, sondern bedeutet auch, dass die Beziehung zwischen Tabellen nicht besteht vollständig verstanden - da die verschiedenen JOIN-Typen unterschiedliche Informationen zurückgeben können, weil sie verschiedene Dinge bedeuten.

In der Regel sind INNER JOINs sehr optimiererfreundlich, da dadurch verschiedene Filterkriterien aus Ihrer WHERE-Klausel und der JOIN-Bedingung um einiges mehr verschoben werden können, um die Index-Scans oder Tabellen-Scans zu verbessern. Einschränkungen der referenziellen Integrität können dem Optimierer auch Informationen über Daten geben, die auf beiden Seiten garantiert sind.

Sie sollten Ihre Ausführungspläne überprüfen und sich Ihre Indexierungsstrategien ansehen. Idealerweise möchten Sie enge, abdeckende Indizes und Sie möchten in Ihren Plänen Index-Suchvorgänge, Index-Scans, Tabellen-Scans (in der Reihenfolge ihrer Präferenz) sehen.

Normalerweise möchten Sie, dass Ihr Modell für die Transaktionsverarbeitung normalisiert und für die Berichterstellung denormalisiert wird, aber zwei Modelle sind am Anfang lästig. Daher versuchen Sie zunächst, Berichte und Analysen zu den normalisierten Daten zu erstellen eine Weile mit besseren Indizes und Blick auf die Ausführungspläne.

Wenn Ihre Berichterstattung auf einer gut indizierten Normalform zu schlecht wird, würde ich die Daten vielleicht in ein dimensionales Modell umwandeln (siehe Kimballs Methodik) mit Sternschemata, die sehr einfache Schemata für das Reporting haben ( typischerweise alle INNER JOINs und ein einfacher Stern) und kann sehr gut auf traditionellen Datenbanksystemen optimiert werden.

    
Cade Roux 30.03.2010 16:06
quelle

Tags und Links