分页性能

现在假如啊,主键为id且是自增的,并且是连续的(不存在断点,),那么,这个语句 select * from xx limit 20000,10   跟这句 select * from xx where id>20000 limit 10.

取出的是相同的结果,但是前者的性能要远远落后于后者。因为,前者虽然是取2万往后的十条,但是,他是先取出2万零10条,然后从结果中筛选出后十条。而后者是直接先定位到2万条,然后再取后十条,也就是说,前者遍历了2万零10行数据,而后者精遍历我们需要的那几条 这就引出了分页的性能的差异

就比如网站常见的每页显示十条数据,那我们在选择sql语句的时候,就不应该这样了:

第一页显示的数据:

select * from xx limit 0,10

第二页显示的数据:

select * from xx limit 10,10

第3页显示的数据:

select * from xx limit 20,10

这样随着显示的页数越来越大,查找性能直线下降。

我们需要这样:

第一页显示的数据:

select * from xx where id >00 limit 10

第二页显示的数据:

select * from xx where id>10 limit 10

第3页显示的数据:

select * from xx where id >20 limit 10

第n页:

select * from xx where id>(n-1)*10 limit 10

但是这样还有一个问题:

我们前面假设了,id是连续的,但实际上,Id是不连续的,比如要显示的是一个个人主页的微博,每页同样是显示10条微博,他不可能一直是写,他也可能把过去的某条微博给删除了,那么这个时候这条数据删除了,id也不存在了,id也就不连续了,所以会出现这样,第二页的起始id可能是11,然后结束id变为了56.也就是说,对于多少多少页,我们是无法立刻预知到这一页的起始id和结束Id,那么select * from xx where id>(n-1)*10 limit 10.这样的语句显然就不行了.如果访客直接要访问第200页,那么我们还得计算200页的起始id

计算起始id:

select id from xx limit 2000,1 

有人会问了,你这个计算起始id,跟前面的第一种方案的分页不一样吗?不一样的,第一种方案是select * ,而这个只取id,如果是只取索引,这种只需要查索引表就能查到,叫做覆盖索引。覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行

(关于索引的原理的知识点:select * from xx where id=2;他的执行过程是先读取索引表,拿到id为2的物理指针,然后拿着这个指针,然后再到数据库中获取数据,)

那么这种效率也是快的。

拿到第200也的起始值在进行查找,两个步骤用一条sql语句合起来就是:

select * from xx where id>(select id from xx limit 2000,1) limit 10

那么这样就实现了分页查找的效果。

但我们经常能看到,人家不光有页数,还有上一页,后一页,那么这个时候,就需要在代码中保存当前页面的最小id和最大id 

当访客查看后一页的时候,执行sql

select * from xx where id > max_id limit 10;

当访客查看前一页的时候,执行sql

select * from xx where id < min_id order by id desc limit 10;

原文地址:https://www.cnblogs.com/saolv/p/10212125.html