Wie kann die Abfrage mit vielen Joins optimiert werden?

8

Ich habe eine einfache, aber lange Abfrage, die den Inhalt des Ergebnisses zählt, dauert etwa 14 Sekunden. Die Zählung selbst in der Haupttabelle dauert weniger als eine Sekunde, aber nach einer Mehrfachverbindung ist die Verzögerung wie folgt zu hoch.

%Vor%

Die Ausgabe von explain ist

%Vor%

Update 1 Die obige Abfrage wurde mit der dynamischen where-Anweisung $sql = $sql . "Where ". $whereFilter verwendet, aber die i-Datei wurde in einfacher Form übergeben. Also bedenken Sie nicht, dass die Antwort nur die Joins löscht:)

Update 2 Hier ist ein Beispiel für dynamische Filterung

%Vor%

Aber im Startfall ist das in unserem Fall keine wo

    
Eslam Sameh Ahmed 12.08.2016, 17:30
quelle

6 Antworten

7

Linke Joins immer geben eine Zeile aus der ersten Tabelle zurück, können jedoch mehrere Zeilen zurückgeben, wenn mehrere übereinstimmende Zeilen vorhanden sind. Da Sie jedoch bestimmte Besuchsreihen zählen, ist das Zusammenfassen mit einer anderen Tabelle beim Zählen der einzelnen Besuche dasselbe wie das Zählen der Besuchsreihen. Daher sind die einzigen Joins, die das Ergebnis beeinflussen, innere Joins, so dass Sie alle "vollständig" links verbundenen Tabellen entfernen können, ohne das Ergebnis zu beeinflussen.

Was ich mit "vollständig" meine, ist, dass einige links verbundene Tabellen effektiv innerlich verbunden sind; Der innere Join zu specialty erfordert, dass der Join zu clients erfolgreich ist und somit auch ein innerer Join ist, der wiederum die Verknüpfung zu clients_locations benötigt, um erfolgreich zu sein und somit auch ein innerer Join zu sein.

Ihre Abfrage (wie gebucht) kann reduziert werden auf:

%Vor%

Das Entfernen all dieser unnötigen Joins wird jedoch die Laufzeit Ihrer Abfrage erheblich verbessern, nicht nur weil weniger Joins erforderlich sind, sondern auch, weil die resultierende Rowset-Größe enorm sein kann, wenn Sie bedenken, dass die Größe das Produkt der Übereinstimmungen in allen Tabellen (nicht die Summe .

Um maximale Leistung zu erzielen, erstellen Sie einen abdeckenden Index für alle id-and-fk-Spalten:

%Vor%

so können nur Index-Scans verwendet werden, wo dies möglich ist. Ich nehme an, dass es Indizes für die PK-Spalten gibt.

    
Bohemian 17.08.2016 00:20
quelle
3

Sie scheinen keine (oder viel) absichtliche Filterung zu haben. Wenn Sie die Anzahl der Besuche in calls wissen möchten, würde ich vorschlagen:

%Vor%     
Gordon Linoff 12.08.2016 17:36
quelle
3

Um den gesamten Prozess zu optimieren, können Sie das vor-wo-SQL dynamisch nach den anzuwendenden Filtern erstellen. Wie:

%Vor%

Wenn Sie mehrere Filter verwenden, können Sie alle inneren / linken Join-Strings in ein Array einfügen und nach der Analyse der Anfrage können Sie Ihr $preSQL mit dem Minimum an Joins erstellen.

    
Geo Halkiadakis 18.08.2016 11:00
quelle
1

Verwenden Sie COUNT (CASE WHEN visit_id !="" DANN 1 ENDE) als Besuch.

Hoffe, das wird helfen

    
premi 20.08.2016 10:36
quelle
1

Ist es nicht nur:

%Vor%

weil alle linken äußeren Joins auch eine visits.id zurückgeben, wenn es keine übereinstimmenden Clients gibt, ... sollten Aufrufe und IDs eindeutig sein?

Unterschiedlicher Hinweis: Der eine innere Join ist auch nur wirksam, wenn ein Client existiert. Wenn sie innere Joins benötigen, müssen sie im Allgemeinen so nah wie möglich an die Quellentabelle gesetzt werden. In Ihrem Beispiel wäre es also am besten in der Zeile nach "Linke Join-Clients" gewesen.

    
Alim Özdemir 22.08.2016 10:06
quelle
0

Ich habe deine Idee nicht zu sehr verstanden, besonders deinen INNER JOIN, der INNER JOINs etwas LINKS transformieren wird, es scheint seltsam, aber lass uns eine Lösung versuchen:

Normalerweise haben die LINKEN VERBINDUNGEN eine sehr schlechte Leistung, und ich denke, dass Sie sie nur brauchen werden, wenn Sie sie in der WHERE-Klausel verwenden, dann können Sie sie nur mit INNER JOIN einschließen, wenn Sie sie verwenden. Zum Beispiel:

%Vor%

Ich denke, es wird Ihrer Leistung helfen und es wird funktionieren, wie Sie brauchen.

    
Jardel Novaes 23.08.2016 19:46
quelle