简而言之:一个包含超过1600万条记录的表[大小为2GB]。当使用ORDER BY *primary_key*时,SELECT的LIMIT偏移量越高,查询就越慢
So
SELECT * FROM large ORDER BY `id` LIMIT 0, 30
花费远远少于
SELECT * FROM large ORDER BY `id` LIMIT 10000, 30
只订购了30张唱片,两者都一样。这不是ORDER BY的开销。
现在,当获取最近的30行时,大约需要180秒。如何优化这个简单的查询?
MySQL不能直接到第10000条记录(或者你建议的第80000个字节),因为它不能假设它是这样打包/排序的(或者它有从1到10000的连续值)。尽管实际上可能是这样,但MySQL不能假设没有漏洞/空白/删除的id。
因此,正如bobs所指出的,MySQL将不得不在找到要返回的30行之前获取10000行(或在id上遍历索引的10000个条目)。
编辑:为了说明我的观点
请注意,尽管
SELECT * FROM large ORDER BY id LIMIT 10000, 30
会很慢,
SELECT * FROM large WHERE id > 10000 ORDER BY id LIMIT 30
将是fast(er),并且将返回相同的结果,前提是没有缺失的id(即间隙)。
较高的偏移量会降低查询的速度,这是正常的,因为查询需要计算第一个OFFSET + LIMIT记录(并且只取其中的LIMIT)。该值越高,查询运行的时间就越长。
查询不能直接转到OFFSET,因为首先,记录的长度可能不同,其次,删除的记录之间可能存在空白。它需要检查和计数途中的每一条记录。
假设id是MyISAM表的主键,或者是InnoDB表中唯一的非主键字段,你可以使用下面的技巧来加快速度:
SELECT t.*
FROM (
SELECT id
FROM mytable
ORDER BY
id
LIMIT 10000, 30
) q
JOIN mytable t
ON t.id = q.id
请看这篇文章:
MySQL ORDER BY / LIMIT性能:晚行查找
我发现了一个有趣的例子来优化SELECT查询ORDER BY id LIMIT X,Y。
我有3500万行,所以我花了2分钟找到一个行范围。
诀窍是这样的:
select id, name, address, phone
FROM customers
WHERE id > 990
ORDER BY id LIMIT 1000;
只要把WHERE和最后一个id放在一起,性能就会提高很多。对我来说是2分钟到1秒:)
这里还有其他有趣的技巧:http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/
它也适用于字符串