2016-03-29 15 views
2

私は実行に非常に時間がかかる(約30秒)次のクエリがあります。このクエリを最適化する方法はありますか?MySQLクエリ最適化のヘルプが必要

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

おそらく、インデックスで始めることができます。 – Nitish

+0

これは問題の説明ではなく、いくつかの数字とSQLクエリです。データベースのスキーマ(インデックスの構造やテーブル間の接続を含むテーブルの構造)とは何か、実行計画とは何か、レコード数とは何ですか?クエリの最適化は、いくつかのベストプラクティスを適用するだけではなく、作業しているデータを知る必要があります。私たちはあなたのデータについて何も知らない。あなたのデータを知っていますか?あなたは私たちを教えてくれますか? – Pred

答えて

0

@Gordon Linoffはすでに指摘しているように、インデックスを定義する必要があります。ただし、クエリをさらに進めるにはいくつかのことがあります。よくあなたのテーブルの順序を定義することが確かに優れているので、我々はこれが実際れる保証はありませんにもかかわらず、よりエレガントなコードである。この

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 

にこの

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 

を変更します最初のものよりも早くなります。しかし、このより良い順序で、私たちは次のステップに進みます。 where句は、joinが完了した後に実行されるため、大きな多次元のレコードセットがメモリにロードされ、行がフィルタリングされます。 on条件は、以前実行し、その次のステップでは、このように、whereを変更し、on条件にその状態を移行することです:

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 

この方法では、不要なレコードは彼ら以来、時間を短縮し、join INGながら除外されますすべてがメモリにロードされてからフィルタリングされるわけではありません。最後の手順は、コードの可読性が低下するため、クエリがまだ遅い場合にのみ実行する必要があります。深刻なフィルタ(行数を大幅に減らす)または厳しいプロジェクション(多くのクエリを含む)を持つjoinを修正することができます大規模なフィールドが必要でしたが、小さなサブセットしか必要としませんでした)。例:

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 

この最終修正プレフィルターlはとjoinを開始するレコードのほんの一握りがあることを確認します。

+0

これはワッフルのように聞こえる。ここに記載されているステートメントをサポートするためのデータはありますか? – Strawberry

+0

変更の一部は実行計画に多少の影響を与えるかもしれませんが、データの分布、インデックス、インデックスの構造などに大きく依存します。データベースの事実を知らなくても、これはちょうど推測です。私はすべてのテーブルが必要なのかどうかも分かりません(このステートメントの真実は、私たちが知らないキーとカラムのプロパティに依存します)。 – Pred

+0

確かに、onは、レコードが結合されているときに正確に実行される場所です。ここでは(から継承)が既に実行されていると仮定します。いくつかのRDBMSにはいくつかのソースがあります(http://stackoverflow.com/questions/10133356/where-clause-before-inner-joinおよびhttps://msdn.microsoft.com/en-us/library/ms189499.aspx)それについて私の実験もこれを確認した。subselectは実際にmysqlにテーブルから行をフィルタリングして結合させ、フィルタリングされた各レコードは一度しか考慮されません –

2

ジョインに使用するすべての列にインデックスを付ける必要があります。さらに重要なことは、あなたはdb.vehicleにインデックスしている必要があります。これはwhere句の

db_vehicle(name, model, engine_type, id) 

を使用する必要がありますし、クエリをスピードアップ。