[英]mysql innodb select offset slow
我在表中有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
任何建议或想法赞赏。
这都是关于缓存的。
简而言之, OFFSET
糟糕。 它必须读取并忽略所有“偏移”行,然后传递“限制”行。
在跳过行时,它必须获取行 - 如果它们在磁盘上,这需要时间; 如果它们被缓存在RAM中,它会快得多。 (通常快10倍。)
在您的情况下可能发生的情况:第一个查询在RAM中发现很少(如果有)行,因此它必须包含大部分或全部1999950行。
然后你的第二个查询快速扫描1999950行,然后从磁盘中取出最后的50行。 (或者可能最后的50个已经出现,因为I / O的单位是记录的“块”。)
使用LIMIT
和/或OFFSET
, EXPLAIN
很少提供任何线索 - 它通常提供表中总行数的估计值 。
您的示例还有另一个问题......您没有ORDER BY
。 因此,引擎可以随意提供它喜欢的任何行。 通常它是可预测的,但有时你会得到惊喜。
但是,一旦添加了ORDER BY
, 即使在获取第一条记录之前 ,也可能需要临时表和排序! 也就是说, SELECT ... ORDER BY .. LIMIT 50
可能和所有其他的一样慢 - 如果你按照索引等不方便的顺序进行排序。
了解在分页网页时OFFSET如何糟糕 。 这包括“记住你离开的地方”的解决方法。 这显示了如何有效地获得接下来的1000行,即使在ID中存在间隙。
有一个解决方案可以更快地完成它,但只有当你有一个主键int并且在这个表中没有间隙时它才会起作用。 我的意思是你不允许删除。 在这种情况下,您的查询将如下所示:
SELECT * FROM table_records where id >= 1999950 order by id LIMIT 50;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.