我有一个问题:
mysql> explain SELECT *
FROM OTHERS_TINY_URL_TBL
WHERE LINK_TYPE = 'BITLY'
AND URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11'
AND MODIFIED_TM >= '2016-03-13 21:09:43'
AND MODIFIED_TM <= '2017-03-13 21:09:43'
AND POST_ID < 0
ORDER BY MODIFIED_TM DESC
LIMIT 1000\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: OTHERS_TINY_URL_TBL
type: range
possible_keys: XIE1_OTHERS_TINY_URL_TBL,XIE2_OTHERS_TINY_URL_TBL,XIE5_OTHERS_TINY_URL_TBL
key: XIE5_OTHERS_TINY_URL_TBL
key_len: 4
ref: NULL
rows: 47168
Extra: Using index condition; Using where
1 row in set (0.00 sec)
ERROR:
No query specified
我不知道为什么扫描这么多行。似乎ORDER BY和LIMIT使其效率低下
没有ORDER BY和LIMIT:
mysql> explain SELECT *
FROM OTHERS_TINY_URL_TBL
WHERE LINK_TYPE = 'BITLY'
AND URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11'
AND MODIFIED_TM >= '2016-03-13 21:09:43'
AND MODIFIED_TM <= '2017-03-13 21:09:43'
AND POST_ID < 0\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: OTHERS_TINY_URL_TBL
type: range
possible_keys: XIE1_OTHERS_TINY_URL_TBL,XIE2_OTHERS_TINY_URL_TBL,XIE5_OTHERS_TINY_URL_TBL
key: XIE2_OTHERS_TINY_URL_TBL
key_len: 9
ref: NULL
rows: 4950
Extra: Using index condition; Using where
1 row in set (0.00 sec)
ERROR:
No query specified
过滤集中只有85行:
mysql> SELECT count(*)
FROM OTHERS_TINY_URL_TBL
WHERE LINK_TYPE = 'BITLY'
AND URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11'
AND MODIFIED_TM >= '2016-03-13 21:09:43'
AND MODIFIED_TM <= '2017-03-13 21:09:43'
AND POST_ID < 0\G;
*************************** 1. row ***************************
count(*): 85
1 row in set (0.02 sec)
ERROR:
No query specified
创建在较少行数上扫描的嵌套查询:
mysql> explain SELECT *
FROM
(
SELECT *
from OTHERS_TINY_URL_TBL
where URL_SHORTNER_ID = '5434e3b9e4b03aa06f25da11'
AND MODIFIED_TM >= '2016-03-13 21:09:43'
AND MODIFIED_TM <= '2017-03-13 21:09:43'
AND POST_ID < 0
) inner_t
where true
ORDER BY MODIFIED_TM DESC
LIMIT 1000\G;
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4950
Extra: Using filesort
*************************** 2. row ***************************
id: 2
select_type: DERIVED
table: OTHERS_TINY_URL_TBL
type: range
possible_keys: XIE2_OTHERS_TINY_URL_TBL,XIE5_OTHERS_TINY_URL_TBL
key: XIE2_OTHERS_TINY_URL_TBL
key_len: 9
ref: NULL
rows: 4950
Extra: Using index condition; Using where
2 rows in set (0.00 sec)
ERROR:
No query specified
为什么第一个查询效率低下?
答案 0 :(得分:2)
首先,重要的是要注意rows
中的数字只是一个估计,基于一些统计数据,并且根据您的MySQL版本,在规划阶段对您的索引进行一些随机查找。有时它可能完全错误(并且基于这些估计,MySQL可能会选择较慢的执行计划)。这就是为什么,如果你对MySQL没有的数据有所了解,可以通过例如优化查询来优化查询。强制MySQL不想选择的索引。
此外,MySQL尝试最小化的唯一相关值是总执行时间。它可能与它必须读取的行数相关联,但不必(例如,如果您不必执行文件排序)。即使它通常可能选择一个好的策略,它可能取决于您的实际数据,如果它实际上是最快的。尝试例如limit 10
模拟而不是85,4000行将满足您的搜索条件。这完全取决于您的数据,而不是查询本身 - 并且MySQL必须在执行查询之前决定如何执行查询。
但一般情况下,由于您的查询使用的是不同的索引,因此预计您的查询在rows
中会有不同的数字。
第一个查询将使用MODIFIED_TM
上的索引,该索引遍历给定日期范围内的所有行。估计是47168行位于此范围内。对于所有这些行,它将检查其他列以查找其他条件。
您的第二个查询将使用不同列上的索引,可能是LINK_TYPE
。您必须添加索引定义以使其清晰,并且可以例如也是URL_SHORTNER_ID
,但对于以下内容,我假设索引是(仅)LINK_TYPE
。估计是4950行具有此LINK_TYPE
。这实际上往往是一个糟糕的估计,你可以通过例如检查正确的数字。 SELECT count(*) FROM OTHERS_TINY_URL_TBL WHERE LINK_TYPE = 'BITLY'
。如果这些行与其他条件匹配,则必须检查这些行中的每一行。
MySQL还不知道最终只能找到85行,并且检查4950行和订购剩余的85行可能比检查已经按正确顺序排列的47168行更快(和所以不必事后订购,这是MySQL通常试图阻止的相对较慢的操作)。您也可能会感到幸运:可能会发生这些47168行中的前1000行必须纠正link_type
,url_shortener_id
和post_id
,因此它必须只检查1000行而不是检查4950行并进行排序。但这仅取决于您的数据。如果你对MySQL没有的数据有所了解,你应该使用优化器提示,例如:强制使用不同的索引。或者欺骗MySQL,例如通过使用你的第三个查询 - 虽然MySQL 5.7可能会诱骗你,因为它实际上应该优化子查询。
幸运的是,有一个更好的解决方案。您的第一个查询有一个完美的索引(这也会同时改善您的第二个查询):OTHERS_TINY_URL_TBL(URL_SHORTNER_ID, LINK_TYPE, MODIFIED_TM)
。