我在 MYSQL 数据库中有一个 Flow 表。它有以下列taskId,wName,key,status,envNo,updateTime等。没有与其他表的连接。它具有以下索引 index1(taskId)、index2(wName,key,name,evnNo)、index3(name)、index4(key)、index5(updateTime)、index6 (环境号)
查询1:
Below query giving me 11 records
select * from Flow where status = 0 and wName = 'abc' order by updateTime LIMIT 50
Running Explain on above query giving below response:
type: index, possible_key: index2, actual_key: index5, rows : 3000, Filtered: 0.05, Extra : Using Where
查询2:
Below query giving me 50 records
select * from Flow where status = 0 and wName = 'xyz' order by updateTime LIMIT 50
Running Explain on above query giving below response:
type: index, possible_key: index2, actual_key: index5, rows : 108, Filtered: 1.84, Extra : Using Where
下面是指定wName在流表中的可用记录总数。
select count(*) from Flow where wName = 'abc' - it gives me 3000 records.
select count(*) from Flow where wName = 'xyz' - it gives me 120000 records.
这里的问题是 Query1 在 20 秒内响应,而 Query2 在不到 1 秒内响应。为什么会发生这种情况? 与查询 2 相比,查询 1 的数据非常少。
当我删除
LIMIT 50
时,两个查询都以毫秒为单位响应。
当我删除
order by updateTime
时,两个查询都以毫秒为单位响应。
请注意,我无法更新索引,因为除了这种情况之外,一切都运行良好。
到目前为止,我得到了以下根本原因。
如果是以上原因,我该如何证明这些原因?如果不是这个原因,那么可能的原因是什么?
根据您的评论,您最感兴趣的是了解为什么 Query1 比 Query2 慢,即使它返回的行数较少,所以我从它开始。
使用
updateTime
上的索引(即按该列排序),您的查询将遍历表并查找适合您条件的行。
Query2 在找到 50 行后停止。
Query1 不能提前停止,因为表中只有 13 行适合,所以它必须读取整个表到底。这显然比提前停止要慢。
为了测试这一点,您可以将限制增加到大于 Query2 可以获得的行的值(因此它也不能提前停止),并且您应该获得两者相似的执行时间 - 除非 MySQL 决定采取那么不同的索引。
您的查询的一个最佳索引是
(wName, status, updateTime)
。
但是由于您无法添加它,因此从可用索引列表中进行选择(并对数据分布进行一些假设),我的猜测是
wName, ...
上的索引是最好的。由于大多数行的 status
似乎与 0 不同,因此按 updateTime
排序可能并不像 MySQL 想象的那么相关。
这可能也是您删除
LIMIT 50
时MySQL选择的索引(尽管您没有提到您的主键是什么,这也可能是一个选项)。
您可以强制 MySQL 使用该索引,例如尝试
select * from Flow force index (index2)
where status = 0 and wName = 'abc' order by updateTime LIMIT 50
Query2 现在将比 Query1 慢,但可能不会比现在慢。
请注意,这特定于您选择的值和数据分布,例如如果您使用
where status = 1
(或任何最常见的)执行相同的查询,当前索引可能会更快(尽管我的猜测是它不会)。如果您在不同情况下使用此查询,请记住(并测试)这一点,例如,如果用户可以选择“状态”的值,并且您根据用户的选择运行此查询。