MySQL 查询优化 - 子查询 & 使用 where;使用临时的;使用文件排序
Posted
技术标签:
【中文标题】MySQL 查询优化 - 子查询 & 使用 where;使用临时的;使用文件排序【英文标题】:MySQL Query Optimisation - Sub Queries & Using where; Using temporary; Using filesort 【发布时间】:2013-02-16 00:26:04 【问题描述】:我正在寻找优化以下 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 |
+----+--------------------+-------+--------+--------------------------------------+-----------------+---------+------------------------+------+----------------------------------------------+
我知道问题是“使用 where;使用临时;使用文件排序”和子查询,但我不确定如何重写它以提高性能。
提前感谢任何可以帮助我解决此类问题的建议。
皮特
【问题讨论】:
【参考方案1】:在您的查询中,您提供了谓词来限制 forecast
集,但正在无序地加入您的表。 mysql 优化器做了一些工作并在预测中使用day
键,并在加入其他表之前使用f.day IN ('2012-12-28', '2012-12-29')
限制预测集。优化器无法在加入之前使用您的依赖子查询(看起来没有必要)来进一步限制condition_id
、temperature_high
和temperature_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
【讨论】:
感谢这双令人神清气爽的眼睛。你完全正确,我不需要每天循环创建子查询,因为每天的条件和温度都是相同的。我认为在不同日子选择不同条件的能力是我留下的。干杯!以上是关于MySQL 查询优化 - 子查询 & 使用 where;使用临时的;使用文件排序的主要内容,如果未能解决你的问题,请参考以下文章