mysql innodb选择偏移慢

时间:2016-08-30 07:28:12

标签: mysql innodb

我在表中有29900000条记录,偏移消耗了太多的查询执行时间

SELECT * FROM table_records LIMIT 50 OFFSET 1999950
this query taking 33.087 sec

我已将偏移量更改为2000000

SELECT * FROM table_records LIMIT 50 OFFSET 2000000
this query taking 2.030 sec

的解释

EXPLAIN SELECT * FROM table_records LIMIT 50 OFFSET 29941250


id | select_type | table         | type   | possible_keys | key     | key_len | ref    |rows     | Extra   
1  | SIMPLE      | table_records | index  | (NULL)        | PRIMARY | 4       | (NULL) |29900771 |         

我已删除偏移设置为限制

SELECT * FROM table_records LIMIT 50
this query taking 0.002 sec

赞赏任何建议或想法。

2 个答案:

答案 0 :(得分:2)

这都是关于缓存的。

简单地说,OFFSET很糟糕。它必须读取并忽略所有“偏移”行,然后传递“限制”行。

当跳过行时,它必须获取行 - 如果它们在磁盘上,这需要时间;如果它们被缓存在RAM中,它会快得多。 (通常快10倍。)

在您的情况下发生了可能:第一个查询在RAM中找到了很少的行(如果有的话),因此它必须包含大部分或全部1999950行。

然后你的第二个查询快速扫描1999950行,然后从磁盘中取出最后的50行。 (或者可能最后50个已经出现,因为I / O的单位是记录的“块”。)

使用LIMIT和/或OFFSETEXPLAIN很少提供任何线索 - 它通常会提供表格中总行数的估算值

您的示例还有另一个问题......您没有ORDER BY。因此,引擎可以随意提供它喜欢的任何行。通常它是可预测的,但有时你会得到惊喜。

但是,一旦添加ORDER BY可能需要成为临时表,并在获取第一条记录之前对进行排序!也就是说,SELECT ... ORDER BY .. LIMIT 50 可能与所有其他人一样慢 - 如果您按照索引等不方便的顺序进行排序。

how OFFSET sucks when paginating web pages。这包括“记住你离开的地方”的解决方法。并且this显示了如何有效地获得接下来的1000行,即使在ID中存在间隙。

答案 1 :(得分:1)

有一个解决方案可以更快地完成它,但只有当你有一个主键int并且在这个表中没有间隙时它才会起作用。我的意思是你不允许删除。在这种情况下,您的查询将如下所示:

SELECT * FROM table_records where id >= 1999950 order by id LIMIT 50;