优化慢 SQL 查询

Posted

技术标签:

【中文标题】优化慢 SQL 查询【英文标题】:Optimising slow SQL query 【发布时间】:2011-07-09 10:43:26 【问题描述】:

我在更改 SQL 查询以更快地执行时遇到问题。我需要检索特定时间间隔的第一行和最后一行。例如,我正在查找数据库中某个特定时间间隔(1 小时、24 小时)的第一个和最后一个日期。我有这个工作的 sql 语句,我正在使用 php 执行它:

$query = "
    SELECT Date, RainABS
    FROM ws3600
    WHERE Date IN (
        (
            SELECT MIN(Date)
            FROM ws3600
            WHERE Date >= '" . $timeInterval1 . "'
                AND Date <= '" . $timeInterval2 . "'
        ),
        (
            SELECT MAX(Date)
            FROM ws3600
            WHERE Date >= '" . $timeInterval1 . "'
                AND Date <= '" . $timeInterval2 . "'
        )
    )
";

从查询中可以看出,表名是ws3600,我检索的参数是Date和RainABS。我正在使用 IN 运算符和两个内部选择语句。

问题是,在执行时:

$result = mysql_query($query);

这需要很长时间。我用这段代码测量了它:

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;

$result = mysql_query($query);

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);

平均耗时 0.28 秒。问题是我必须执行 24 个这样的语句,平均累积到 6,72 秒。我知道我可能应该摆脱内部选择语句,但是我不知道如何获得第一行和最后一行?

【问题讨论】:

你有日期的索引吗? 不,我没有日期索引。我在 id 上有主索引,这个查询我不需要它。您是否建议我在属性 Date 上创建二级 B+ 树索引以加快查询速度? @Jernej 这个查询使用 Date 作为过滤器,所以我认为索引会有很大帮助。 哇,Date 上的 BTREE 索引确实加快了速度。现在,使用 Flimzy 解决方案只需 2*10^-4 秒即可完成某个查询,而之前的 0.16 秒。 【参考方案1】:

要摆脱带有 MIN 或 MAX 的内部选择,答案通常是 ORDER BY 和 LIMIT。

类似这样的:

SELECT Date, RainABS
FROM ws3600
WHERE Date >= '" . $timeInterval1 . "'
    AND Date <= '" . $timeInterval2 . "
ORDER BY Date ASC
LIMIT 1

UNION

SELECT Date, RainABS
FROM ws3600
WHERE Date >= '" . $timeInterval1 . "'
    AND Date <= '" . $timeInterval2 . "
ORDER BY Date DESC
LIMIT 1;

【讨论】:

哦,日期字段上的索引可能会有所帮助,但插入成本会略有增加。 @Szocske 为什么你认为这更快? 我还没有尝试过这个解决方案,但是几分钟前我认为 Flimzy 在这里发布了另一个解决方案现在丢失了:SELECT Date, RainABS FROM ws3600 JOIN ( SELECT MIN(Date) AS min, MAX(Date) AS max FROM ws3600 WHERE Date >= '2010-09-17 02:00:00' AND Date 这个解决方案从平均 0.28 秒缩短到 0.16 秒,但是在运行 24 次查询时,它仍然平均需要 3.84 秒,但比 6.72 秒要好很多。 @Flimzy 是的,我也想知道。你为什么删除你的查询? :)【参考方案2】:

这应该会加快速度,将查询数量减少一。

SELECT Date, RainABS
FROM ws3600
JOIN (
    SELECT
        MIN(Date) AS min,
        MAX(Date) AS max
    FROM ws3600
    WHERE Date >= '" . $timeInterval1 . "'
        AND Date <= '" . $timeInterval2 . "'
) AS x ON (ws3600.Date = min OR ws3600.Date = max);

编辑: 应大众需求...我将答案留在这里,因为它在“技术上”是正确的,但是,我相信最好的答案是使用两个的 UNION根据 Szocske 的建议进行查询。

【讨论】:

将尝试另一个并比较它的执行时间。 我已经使用了你的解决方案,我在其他帖子中已经说过,在属性日期上使用 BTREE 索引平均从 0.28 秒减少到 0.16 秒。这将平均 0.16 秒降低到平均 2*10^-4 秒。 好吧,我很高兴它起作用了......我很惊讶它比 UNION 表现得更好......但很高兴你找到了答案:) @Flimzy 我认为使用索引时,您的解决方案和@Szocske 解决方案之间确实存在微小差异。问题是在没有索引的情况下尝试查找最大值和最小值比对表进行排序要快。 我也想知道 MySQL 是否足够聪明,可以通过使用索引来优化 MIN() 和 MAX()。如果是这样,即使使用索引,我的查询仍然可能会更快,尽管差异当然变得可以忽略不计。当然没有索引,回Date列的JOIN不会很快……

以上是关于优化慢 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

第15天SQL进阶-查询优化-慢查询日志(SQL 小虚竹)

MySQL如何定位并优化慢查询sql

MySQL优化--02----慢SQL定位慢查询日志

sql查询速度慢如何优化

逆水行舟 —— SQL优化之慢查询和explain以及性能分析

SQL查询优化