我有一个SQL查询需要花费大量时间来评估,因为它在一个非常大的数据集上运行。在尝试改善执行时间时,我发现了以下内容:
执行以下查询时,MySQL服务器需要花费大量时间(最多100秒)
SELECT some_data
FROM table
INNER JOIN anothertable
ON ( table.value =
anothertable.value )
WHERE ( table.parent = 56521
AND table.date >=
'2016-10-19 08:37:45.606947' )
ORDER BY table.date DESC
LIMIT 1
所以我猜测它是查询的排序部分需要花费如此多的执行时间,我手动删除以排序以查看执行中的差异:
SELECT some_data
FROM table
INNER JOIN anothertable
ON ( table.value =
anothertable.value )
WHERE ( table.parent = 56521
AND table.date >=
'2016-10-19 08:37:45.606947' )
LIMIT 1
上面的查询需要0.45秒,并导致一个空的查询集。
我得出结论,我的查询在评估WHERE-Clause之前命令WHOLE数据集。我应该如何形成查询以防止这种行为?为什么会出现这种行为?
这些是用于慢速和快速查询的EXPLAIN表:
Slow
+----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+
| 1 | SIMPLE | A | NULL | index | PRIMARY,D4b797d14e515242e7251754c57b7701 | date | 5 | NULL | 1325 | 0.08 | Using where |
| 1 | SIMPLE | B | NULL | eq_ref | PRIMARY | PRIMARY | 4 | value | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+------------------------------------------+------------------+---------+------------------------------+------+----------+-------------+
Fast:
+----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+
| 1 | SIMPLE | A | NULL | ref | PRIMARY,D4b797d14e515242e7251754c57b7701 | D4b797d14e515242e7251754c57b7701 | 4 | const | 5175 | 100.00 | NULL |
| 1 | SIMPLE | B | NULL | eq_ref | PRIMARY | PRIMARY | 4 | value | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+------------------------------------------+----------------------------------+---------+------------------------------+------+----------+-------+
答案 0 :(得分:1)
MySQL使用date
上的索引进行第一次查询。它可以部分评估where
- 条件(table.date >= '2016-10-19 08:37:45.606947'
),如果合适,它将从您的表中读取parent
(这相对较慢),看它是否也适合。它可以在找到结果后立即停止(因为order by
和limit 1
)。
您的第二个查询使用parent
上的索引(即具有长名称的索引),查找适合的行,然后从表中读取date
- 部分并检查它是否适合太。它必须继续,直到它使用正确的parent
- 值(它使用索引找到)检查所有行,并且它找到的所有行都必须经历一个filesort,并且将返回最新的行。
(我忽略了MySQL也必须检查/执行join
,但在两个查询中都是一样的。)
你显然有更多符合date
条件的行,而不是parent
- 条件,所以它必须做更多相对较慢的表查找,这需要更长的时间。
在这种情况下。根据您的数据,实际上可能会发生通过date
上的索引检查的第一行已经满足parent
条件,并且可能会在那里停止。如果它将使用parent
上的索引,MySQL将被强制检查具有parent
- 值的所有行,然后执行文件排序。 MySQL在一些统计数据的基础上决定,值得冒这个风险。好吧,它选错了。
您可以执行以下操作:
optimize table `table`
(第二个table
是您的表名)来更新您的统计信息。这有时会有所帮助,但通常不会(因为统计数据非常有限)。 ... FROM table force index (D4b797d14e515242e7251754c57b7701) inner join ...
)table(parent, date)
应该(不计算join
的潜在影响)给出比无序查询更快的结果,MySQL将使用它它自己的。