2013-02-16 49 views
0

我期待優化下面MySQL查詢:MySQL查詢優化 - 子查詢和使用哪裏;使用臨時;使用文件排序

SELECT 
    `l`.`id` AS `l__id`, `l`.`latitude` AS `l__latitude`, `l`.`longitude` AS `l__longitude`, `l`.`name` AS `l__name`, `f`.`id` AS `f__id`, `f`.`day` AS `f__day`, `f`.`temperature_low` AS `f__temperature_low`, `f`.`temperature_high` AS `f__temperature_high`, `c`.`id` AS `c__id`, `c`.`name` AS `c__name` 
FROM `location` `l` 
INNER JOIN `forecast` `f` ON `l`.`id` = `f`.`location_id` 
INNER JOIN `condition` `c` ON `f`.`condition_id` = `c`.`id` 
WHERE (
    `f`.`day` IN ('2012-12-28', '2012-12-29') AND 
    EXISTS (
     SELECT 
      `f2`.`id` AS `f2__id` 
     FROM `forecast` `f2` 
     WHERE (
      `f2`.`location_id` = `l`.`id` AND `f2`.`day` = "2012-12-28" AND `f2`.`condition_id` IN (6, 7, 9, 10, 11, 12, 13, 14, 18) AND `f2`.`temperature_high` <= 30 AND `f2`.`temperature_low` >= 0 
     ) 
    ) AND 
    EXISTS (
     SELECT 
      `f3`.`id` AS `f3__id` 
     FROM `forecast` `f3` 
     WHERE (
      `f3`.`location_id` = `l`.`id` AND `f3`.`day` = "2012-12-29" AND `f3`.`condition_id` IN (6, 7, 9, 10, 11, 12, 13, 14, 18) AND `f3`.`temperature_high` <= 30 AND `f3`.`temperature_low` >= 0 
     ) 
    ) 
    AND `l`.`latitude` IS NOT NULL AND `l`.`longitude` IS NOT NULL 
); 

運行的EXPLAIN給出了下面的輸出:

+----+--------------------+-------+--------+--------------------------------------+-----------------+---------+------------------------+------+----------------------------------------------+ 
| id | select_type  | table | type |   possible_keys    |  key  | key_len |   ref   | rows |     Extra      | 
+----+--------------------+-------+--------+--------------------------------------+-----------------+---------+------------------------+------+----------------------------------------------+ 
| 1 | PRIMARY   | f  | range | location_id_idx,condition_id_idx,day | day    |  3 | NULL     | 1298 | Using where; Using temporary; Using filesort | 
| 1 | PRIMARY   | l  | eq_ref | PRIMARY        | PRIMARY   |  8 | weather.f.location_id | 1 | Using where         | 
| 1 | PRIMARY   | c  | eq_ref | PRIMARY        | PRIMARY   |  8 | weather.f.condition_id | 1 |            | 
| 3 | DEPENDENT SUBQUERY | f3 | ref | location_id_idx,condition_id_idx,day | location_id_idx |  9 | weather.l.id   | 276 | Using where         | 
| 2 | DEPENDENT SUBQUERY | f2 | ref | location_id_idx,condition_id_idx,day | location_id_idx |  9 | weather.l.id   | 276 | Using where         | 
+----+--------------------+-------+--------+--------------------------------------+-----------------+---------+------------------------+------+----------------------------------------------+

我明白,問題是「在那裏使用;使用臨時;使用filesort「和子查詢,但我不確定如何重新寫這個表現。

預先感謝任何能幫助我解決未來這類問題的指針。

皮特

回答

1

在查詢您提供的謂詞來限制forecast集但加入您的表壞了。 mysql優化器會執行一些工作,並使用day關鍵字進行預測,並在加入其他表之前使用f.day IN ('2012-12-28', '2012-12-29')限制預測集。優化程序無法使用您的從屬子查詢(看起來不需要)在加入之前進一步限制由condition_idtemperature_hightemperature_low設置的預測,以便在所有連接完成後完成。爲了改進查詢,您應該刪除您的從屬子查詢並將預測集限制在開頭。

SELECT * 
FROM forecast f 
INNER JOIN location l 
    ON l.id = f.location_id AND l.latitude IS NOT NULL AND l.longitude IS NOT NULL 
INNER JOIN condition c 
    ON f.condition_id = c.id 
WHERE f.day IN ('2012-12-28', '2012-12-29') 
    AND f.condition_id IN (6, 7, 9, 10, 11, 12, 13, 14, 18) 
    AND f.temperature_high <= 30 AND f.temperature_low >= 0 
+0

感謝您的新鮮眼睛bmewsing。你完全正確,我不需要每天循環創建子查詢,因爲每天的條件和溫度是相同的。我認爲能夠在不同的日子選擇不同的條件是我遺留下來的。乾杯! – 2013-02-16 11:51:46