表中有 400,000 条记录
表格形成
id(int,pk)
title varchar(255)
body(text)
查询 1
select **title** from qa_question order by id desc limit 300000, 15;
运行时间15秒
查询 2
select **body** from qa_question order by id desc limit 300000, 15;
运行时间1.8秒
我想知道为什么
让我们仔细看看您的查询有ORDER BY id DESC LIMIT 300000, 15.
MySQL 服务器必须做什么才能执行它?首先,它必须根据主索引id以降序获取每条记录。请注意,这必须发生 300k 次。一旦达到 300,000 个计数,服务器才可以开始输出结果行,并且只有 15 个。如果您使用的不是 300k 初始偏移量,而是更小的值,则此查询会运行得更快。
为什么 query1 与 query2 相差 10 倍?这是因为TEXTMySQL中的列链接到父表(未存储在其中)并且检索它们需要额外的查找,但VARCHAR存储在表中。在您的情况下,TEXT列获胜,因为您实际上不需要拉body列,直到您达到第 300,000 行(服务器仅拉body TEXT取对另一个不可见表中的列的相对较小的引用)。但是在title列的情况下,服务器别无选择,只能拉满title列,即使它在 100 字节的范围内,这就是它慢 10 倍的原因。
很难说清楚。这可能是因为第一个查询运行缓慢,但将所有表数据缓存在 RAM 中,所以第二个可以运行得更快。在得出任何结论之前,您应该至少重复所有查询 3 次。
我对你的建议是找到一种方法来LIMIT 300000, 15替换
WHERE id BETWEEN 300000 AND 300014
或等效的,如果可以的话。在这种情况下,服务器将能够利用主索引,而且速度会快如闪电。
这是因为varchar在执行查询之前分配内存,即它使用静态内存分配。因此,即使标题短于 255 个字符,它也会保留 255 个字符的内存。
在这种情况下,您可以使用VARCHAR CHARACTER SET utf8,它是 nvarchar 的别名,它是动态的并根据标题的长度使用内存量。
由于您有 400,000 条记录,这相当多,这会在使用 varchar 时导致更长的运行时间。所以,我的建议是使用VARCHAR CHARACTER SET utf8并避免使用 varchar。