我们知道,limit分页,当翻到比较靠后的页时,查询效率会越来越慢。如这则帖子所述:

浅谈PageHelper插件分页实现原理及大数据量下SQL查询效率问题解决

博主这也是一种不错的思路。其实针对分页这个问题,了解其为什么慢就知道优化方法了,按我的理解如下(不一定说的很准确哈):

(1)以前select * from table order by column limit 100, 10这种方式,分页是怎么分的呢,是从磁盘拿整一个数据页到存储引擎缓冲区,比如 limit 100, 10 那就要按顺序先取出前100条数据,跳过了offset后再拿出第[100,110]这10条数据,如果这条数据字段很多且体积比较大,那么数据页就会比较大,我们知道存储引擎内存页大小是有限制的,如果数据页较大,那可能一次内存页只能存一两条数据,那么每次磁盘IO只能取到一两条,所以要翻掉前100条,那就可能需要非常多次的IO,这就是为什么慢的原因。

(2)针对上述问题,主要有两种优化思路,第一种就是针对“按顺序取前100条”这个问题,那我是不是可以不用取完前面100条就能拿到第[100,110]条呢?方法的话比如改造limit 100,10这个sql,用where id > 100 limit 10,这样的话可以按 id 主键索引先定位到哪个磁盘数据页,然后按顺序取10条数据就好了。

(3)第二种思路是针对“取大数据页到内存进行过滤”的问题,那我能不能把数据页做小,使得一个内存页能容纳更多条数据,从而减少磁盘IO次数?又或者我直接通过索引页来过滤,这样就不需要用原数据页来进行内存计算?这就是类似博主所述的方法,就是通过select id from table limit 100,10先分页查出id,再回表查询将这10个id的数据取出来就好了,因为id是主键索引,所以拿id来内存计算(因为id是主键索引,所以不涉及数据页的内存计算),就比拿一整页数据计算,IO次数要少的多了(甚至,存储引擎可能把id索引页都缓存到cache中了的话,压根都不需要硬盘IO了)。此外,order by的字段尽量要是索引字段,比如order by id,所以建表的时候考虑到要分页查询的话,尽量保证id的自增序就是分页的顺序/逆序,这样分页排序就能直接order by id了。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐