2013-03-22 66 views
1

這需要72秒時:可怕SQL性能

SELECT distinct(meters.id) 
FROM meters, meters_tags, houses_tags, tags 
WHERE (
     tags.name = "xxx" AND ((
      meters_tags.tag_id = tags.id AND 
      meters_tags.meter_id = meters.id 
     ) OR (
      houses_tags.tag_id = tags.id AND 
      houses_tags.house_id = meters.house_id 
     ) 
     ) 
    ); 

這需要0.00秒:

SELECT distinct(meters.id) 
FROM meters, meters_tags, houses_tags, tags 
WHERE (
     tags.name = "xxx" AND ((
      meters_tags.tag_id = tags.id AND 
      meters_tags.meter_id = meters.id 
     ) 
     ) 
    ); 

這需要0.00秒:由本身

SELECT distinct(meters.id) 
FROM meters, meters_tags, houses_tags, tags 
WHERE (
     tags.name = "xxx" AND ((
      houses_tags.tag_id = tags.id AND 
      houses_tags.house_id = meters.house_id 
     ) 
     ) 
    ); 

每兩個查詢的取沒時間,但把它們放在一起需要72秒。我也嘗試將此轉換爲形式(query1)或(查詢)而不是query0 AND((query1)或(query2)),它也很慢。

這裏是描述第一(慢)的查詢的:

+----+-------------+-------------+-------+----------------------------------------------------------------------------------------------------+------------------------------------------+---------+-------+-------+-------------------------------------------------------+ 
| id | select_type | table  | type | possible_keys                      | key          | key_len | ref | rows | Extra             | 
+----+-------------+-------------+-------+----------------------------------------------------------------------------------------------------+------------------------------------------+---------+-------+-------+-------------------------------------------------------+ 
| 1 | SIMPLE  | meters_tags | index | index_meters_tags_on_tag_id_and_meter_id,index_meters_tags_on_tag_id,index_meters_tags_on_meter_id | index_meters_tags_on_tag_id_and_meter_id | 10  | NULL |  1 | Using index; Using temporary       | 
| 1 | SIMPLE  | tags  | ref | PRIMARY,tags_name                     | tags_name        | 258  | const |  1 | Using where; Using index        | 
| 1 | SIMPLE  | meters  | index | PRIMARY,index_meters_on_house_id                 | index_meters_on_house_id     | 5  | NULL | 45389 | Using index; Using join buffer      | 
| 1 | SIMPLE  | houses_tags | index | index_houses_tags_on_tag_id_and_house_id               | index_houses_tags_on_tag_id_and_house_id | 10  | NULL | 7158 | Using where; Using index; Distinct; Using join buffer | 
+----+-------------+-------------+-------+----------------------------------------------------------------------------------------------------+------------------------------------------+---------+-------+-------+-------------------------------------------------------+ 

這些表中沒有一個是大於100k的行大。如果合併這兩個查詢需要很長時間,那麼可能需要很長時間才能運行得如此之快?看起來我需要的所有指標都存在,因爲單獨的子查詢就足夠快了。

+0

它沒有回答這個問題,但你可以只做'(fastquery1)union all(fastquery2)'。這是我在查詢由「或」減緩時使用的技巧。 – m4573r 2013-03-22 15:35:42

+0

謝謝。該查詢是自動生成的 - 有多個子句可以添加到查詢中,每個子句用AND分隔。使用union都會打破這種模式,但沒關係,我可以特別說明這個子句,因爲似乎沒有有效的方法來將其表示爲「正常」子句。 – 2013-03-22 15:53:57

回答

1

仔細查看您的組合查詢;它使用meters_tags計算houses_tags的交叉連接,對重複進行排序並消除重複項,並將其連接到查詢的其餘部分。 yur部分查詢都立即丟棄了houses_tags或者meters_tags,並且只使用了othr。因此戲劇性的速度差異。

建議:學習和使用現代連接語法,如果沒有其他原因,而不是因爲它會幫助您避免這些病理情況,直到您學會識別它們。

+0

JOIN語法是否允許此查詢運行得更快,或者只是簡單地說明查詢會變慢? – 2013-03-22 15:50:30

+0

JOIN語法允許您更容易地識別交叉連接,因此您可以更輕鬆地識別查詢,就像寫入的那樣,將是非高性能的。然後你就知道以另一種方式寫下來。在這種情況下,UNION比Cross Jin更高效。 – 2013-03-22 15:56:19