我有一张包含550.000条记录的表格
SELECT * FROM logs WHERE user = 'user1' ORDER BY date DESC LIMIT 0, 25
此查询需要0.0171秒。没有LIMIT,有3537个结果
SELECT * FROM logs WHERE user = 'user2' ORDER BY date DESC LIMIT 0, 25
此查询需要3.0868秒。没有LIMIT,有13个结果
表键是:
PRIMARY KEY (`id`),
KEY `date` (`date`)
当使用“LIMIT 0,25”时,如果记录少于25,则查询速度变慢。我该如何解决这个问题?
答案 0 :(得分:1)
使用limit 25
允许查询在找到25行时停止。
如果您在550.000中有3537个匹配的行,那么平均而言,它将假定相等的分布,在检查550.000/3537*25 rows = 3887 rows
排序的列表中的date
后找到25行(索引为date
)或根本没有订购的清单。
如果550.000中有13个匹配的行,limit 25
将必须检查所有550.000行(这是行数的141倍),因此我们期望0.0171 sec * 141 = 2.4s
。显然还有其他因素决定了运行时间,但数量级适合。
还有一个效果。不幸的是,date
的索引不包含user
的值,所以MySQL必须在原始表中查找该值,通过在该表中来回跳转(因为数据本身是按顺序排序的)主键)。这比直接读取无序表要慢。
实际上,如果要读取很多行,那么根本不使用索引可能比使用索引更快。您可以强制MySQL不使用它,例如FROM logs IGNORE INDEX (date)
,但这会产生这样的效果,它现在必须完全读取整个表格:最后一行可能是最新的,因此必须在结果集中,因为您按{{1}排序}。所以它可能会减慢你的第一个查询 - 快速读取完整的550.000行可能比通过来回跳跃慢慢读取3887行慢。 (MySQL事先并不知道这一点,所以它选择了 - 因为你的第二个查询显然是错误的。)
那么如何获得更快的结果呢?
拥有date
排序的索引。然后user
的查询可以在13行之后停止,因为它知道没有更多的行。这现在比'user2'
的查询更快,它必须查看3537行,然后按'user1'
对它们进行排序。
因此,您的查询的最佳索引将是date
,因为它知道何时停止查找更多行并且列表已按您希望的方式排序(并且在所有情况下都击败了您的0.0171) 。
索引也需要一些资源(例如,在更新表时更新索引的硬盘空间和时间),因此为每个查询添加完美索引可能会对整个系统产生适得其反的效果。