2016-03-29 12 views
2

Ich habe die folgende Abfrage, die sehr lange dauert (ca. 30 Sekunden) auszuführen. Gibt es eine Möglichkeit, diese Abfrage zu optimieren oder sollte ich es lassen?MySQL Query Optimierung Hilfe benötigt

SELECT l.Name, l.Model, l.Engine_Type, m.ID, g.Name 
FROM db.vehicle_part k 
JOIN db.vehicle l ON k.ID_Vehicle = l.ID 
JOIN db.part m ON k.ID_Part = m.ID 

JOIN db.part_generic_part b ON b.ID_Part = m.ID 
JOIN db.generic_part c ON c.ID = b.ID_Generic_part 
JOIN db.generic_part_name d ON c.ID = d.ID_Generic_Part 
JOIN db.part_category_generic_part e ON c.ID = e.ID_generic_part 
JOIN db.part_category f ON e.ID_category = f.ID 
JOIN db.part_category_name g ON f.ID = g.ID_Part_Category 
JOIN db.lang h ON g.ID_Lang = h.ID 

WHERE l.Name = 'BMW' AND l.Model = '3 (E30)' AND l.Engine_Type= '316 i' AND g.ID_Lang =2 
+0

Vielleicht können Sie mit Indizes beginnen. – Nitish

+0

Dies ist KEINE Beschreibung eines Problems, nur einige Zahlen und eine SQL-Abfrage. Was ist das Schema der Datenbank (die Struktur der Tabellen - einschließlich der Indizes - und die Verbindungen zwischen ihnen), Was ist der geschätzte Ausführungsplan, wie hoch sind die Datensätze? Bei der Optimierung einer Abfrage werden nicht nur einige bewährte Methoden angewendet, sondern auch die Daten, mit denen Sie arbeiten. Wir wissen nichts über Ihre Daten. Kennst du deine Daten? Kannst du uns etwas beibringen? – Pred

Antwort

0

Wie @Gordon Linoff bereits hingewiesen hat, müssen Sie Indizes definieren. Es gibt jedoch einige Dinge, die Sie weiter mit Ihrer Anfrage erledigen können. Es ist sicherlich besser gut die Reihenfolge Ihrer Tabellen zu definieren, so dass wir ändern, um diesen

SELECT l.Name, l.Model, l.Engine_Type, m.ID, g.Name 
FROM db.vehicle_part k 
JOIN db.vehicle l ON k.ID_Vehicle = l.ID 
JOIN db.part m ON k.ID_Part = m.ID 

JOIN db.part_generic_part b ON b.ID_Part = m.ID 
JOIN db.generic_part c ON c.ID = b.ID_Generic_part 
JOIN db.generic_part_name d ON c.ID = d.ID_Generic_Part 
JOIN db.part_category_generic_part e ON c.ID = e.ID_generic_part 
JOIN db.part_category f ON e.ID_category = f.ID 
JOIN db.part_category_name g ON f.ID = g.ID_Part_Category 
JOIN db.lang h ON g.ID_Lang = h.ID 

WHERE l.Name = 'BMW' AND l.Model = '3 (E30)' AND l.Engine_Type= '316 i' AND g.ID_Lang =2 

diesen

SELECT l.Name, l.Model, l.Engine_Type, m.ID, g.Name 
FROM db.vehicle_part k 
JOIN db.vehicle l ON k.ID_Vehicle = l.ID 
JOIN db.part m ON k.ID_Part = m.ID 

JOIN db.part_generic_part b ON b.ID_Part = m.ID 
JOIN db.generic_part c ON c.ID = b.ID_Generic_part 
JOIN db.part_category_generic_part e ON c.ID = e.ID_generic_part 
JOIN db.part_category f ON e.ID_category = f.ID 
JOIN db.part_category_name g ON f.ID = g.ID_Part_Category 
JOIN db.lang h ON g.ID_Lang = h.ID 
JOIN db.generic_part_name d ON c.ID = d.ID_Generic_Part 

WHERE l.Name = 'BMW' AND l.Model = '3 (E30)' AND l.Engine_Type= '316 i' AND g.ID_Lang =2 

Dies ist ein eleganter Code, auch wenn es keine Garantie dafür gibt, dass es tatsächlich sei schneller als der ursprüngliche. Mit dieser besseren Reihenfolge gehen wir jedoch zum nächsten Schritt. Die where-Klausel wird ausgeführt, nachdem die join abgeschlossen ist, so dass Sie einen großen, mehrdimensionalen Satz von Datensätzen in den Arbeitsspeicher geladen haben und die Zeilen ausfiltern. Der on Zustand führt früher, so ist der nächste Schritt die where und wandert seinen Zustand in on Bedingungen zu ändern, wie folgt aus:

SELECT l.Name, l.Model, l.Engine_Type, m.ID, g.Name 
FROM db.vehicle_part k 
JOIN db.vehicle l ON k.ID_Vehicle = l.ID AND l.Name = 'BMW' AND l.Model = '3 (E30)' AND l.Engine_Type= '316 i' 
JOIN db.part m ON k.ID_Part = m.ID 

JOIN db.part_generic_part b ON b.ID_Part = m.ID 
JOIN db.generic_part c ON c.ID = b.ID_Generic_part 
JOIN db.part_category_generic_part e ON c.ID = e.ID_generic_part 
JOIN db.part_category f ON e.ID_category = f.ID 
JOIN db.part_category_name g ON f.ID = g.ID_Part_Category and g.ID_Lang =2 
JOIN db.lang h ON g.ID_Lang = h.ID 
JOIN db.generic_part_name d ON c.ID = d.ID_Generic_Part 

Auf diese Weise wird nicht mehr benötigter Datensätze herausgefiltert, während join ing, Zeit zu reduzieren, da sie werden nicht alle in den Speicher geladen und dann gefiltert. Der letzte Schritt sollte genau dann durchgeführt werden, wenn die Abfrage noch langsam ist, da sie die Lesbarkeit des Codes verringert: Sie können die join s mit einem strengen Filter (drastisch die Anzahl der Zeilen) oder einer schweren Projektion (mit vielen große Felder, aber benötigt nur eine kleine Teilmenge davon, zu benannten Subselects. Beispiel:

SELECT 'BMW', '3 (E30)', '316 i', m.ID, g.Name 
from (select temp.ID from db.vehicle temp where temp.Name = 'BMW' AND temp.Model = '3 (E30)' AND temp.Engine_Type= '316 i') l 
JOIN db.vehicle_part k on l.ID = k.ID_VEHICLE 
JOIN db.part m ON k.ID_Part = m.ID 

JOIN db.part_generic_part b ON b.ID_Part = m.ID 
JOIN db.generic_part c ON c.ID = b.ID_Generic_part 
JOIN db.part_category_generic_part e ON c.ID = e.ID_generic_part 
JOIN db.part_category f ON e.ID_category = f.ID 
JOIN db.part_category_name g ON f.ID = g.ID_Part_Category and g.ID_Lang =2 
JOIN db.lang h ON g.ID_Lang = h.ID 
JOIN db.generic_part_name d ON c.ID = d.ID_Generic_Part 

Diese letzte Änderung prefilters l, um sicherzustellen, gibt es nur eine Handvoll von Datensätzen, die join mit zu beginnen.

+0

Das klingt nach viel Waffel. Irgendwelche Daten, um irgendwelche der gemachten Aussagen zu unterstützen? – Strawberry

+0

Einige der Änderungen können Auswirkungen auf den Ausführungsplan haben, hängen jedoch stark von der Verteilung der Daten, der Indizes, der Struktur der Indizes usw. ab. Auch hier ist es, ohne die Fakten über die Datenbank zu kennen, nur raten . Ich bin mir nicht einmal sicher, ob alle Tabellen notwendig sind (wiederum hängt die Wahrheit dieser Aussage von den Schlüsseln und Spalteneigenschaften ab, die wir nicht kennen). – Pred

+0

Sicherlich wird on genau dann ausgeführt, wenn die Datensätze verbunden werden. Wobei angenommen wird, dass von (zusammen mit den Joins) bereits ausgeführt wird. Es gibt mehrere Quellen in mehreren RDBMS (http://stackoverflow.com/questions/10133356/where-clause-before-inner-join und https://msdn.microsoft.com/en-us/library/ms189499.aspx) darüber und meine Experimente bestätigten dies auch.Tatsächlich zwingt der Subselect mysql, Zeilen aus einer Tabelle zu filtern, bevor sie verbunden werden, und jeder gefilterte Datensatz wird nur einmal berücksichtigt. –

2

Sie sollten Indizes für alle für die Joins verwendeten Spalten haben. Noch wichtiger ist, sollten Sie einen Index für db.vehicle haben:

db_vehicle(name, model, engine_type, id) 

Dies sollte die Abfrage für die where Klausel und beschleunigt werden.