MySQL系列-优化之分页查询

1.分页查询以前先按索引排序

咱们常常会上一些小说网站看小说,他们老是会把最近更新了的小说放在最前面,也就是第一页,而好久没更新的就放在后面了。那么这样网站是如何实现的呢?个人猜测有一张小说表,表里面一个last_update表示最后更新字段,而且对这个字段创建了索引,按last_update从大到小排序以后再按需求的页面大小进行分页。java

那为何分页查询老是要排序呢?mysql

由上面的例子能够看出,这个是需求致使的,并且还有效率因素。下面举例说明:sql

表的描述以下:数据结构

只有id主键索引。优化

假设咱们须要前三条数据,执行sql【explain select * from t1 limit 3;】网站

由于咱们没有进行排序,mysql不知道要哪前三条,是id大呢,还name大呢?,mysql晕了,只能进行全表扫描来获取数据表的前三条数据了。因此范围类型为ALL。.net

当咱们进行排序以后状况如何。执行sql【explain select * from t1 order by id desc limit 3;】3d

能够看到,查询类型为索引扫描,可是rows字段显示咱们最多访问三条数据,因此sql效率挺高。固然,前提是咱们的排序用上了相关的索引,不然的话偷鸡不成蚀把米,弄出一个using filesort。blog

2.千万别使用offset

为何不能使用limit的offset?排序

其实offset是对咱们偏移的数据进行遍历,咱们偏移多少mysql就遍历多少,若是一个offset=1000000,那这条sql就至少要扫描1000000条数据了。

执行sql【explain select * from t1 order by id desc limit 3 offset 15;】

能够看到,访问类型依然是索引扫描,可是rows却变成了18,比以前的3可大多了。

因此千万别用offset,咱们可使用查询来筛选出须要的字段,好比:

能够把上面的sql转化为【select * from t1 where id<=5 and id>=3 order by id desc limit 3】

能够看出查出的数据彻底同样,那么下面的sql效率如何呢?

执行sql【explain select * from t1 where id<=5 and id>=3 order by id desc limit 3;】

优化很是明显,访问类型变成了range,rows变成了3。

3.实现上一页和下一页

通常来讲咱们会弄一个javabean记录查询信息,好比说,当前页数,id最大值,id最小值,须要到的页数。

假设当前页面大小为3,页面id最大值为17,最小值为15。

除了上面第二节讲的让id在一个范围内查询的方法,咱们也可使用下面的方法。

那么下一页就是【select * from t1 where id<15 order by id desc limit 3;】

虽然rows为14,但并不会扫描这么多,获得3条就停,由于rows是一个最大估计值。

上一页就是【select * from t1 where id>17 order by id desc limit 3;】

4.如何实现跳页功能

有时须要进行手动输入页数,好比直接从第1页跳到666页,对于实现跳页功能这个就必需要获取整张表到底有多少数据行了。可是又不能 count(*) 的代价过大,由于mysql必需要全扫描来统计行数,那么 count(*) 如何优化呢?这里就再也不重复讲解了,能够参考个人这篇文章【MySQL系列-优化之count()】。

ok,假设你已经看了个人 count() 优化的文章,同时数据表变成了这样。

下面在继续分析。

由于咱们是按id从大到小进行排序,因此为了实现跳页,咱们必须知道用户当前在第几页,以及页面的大小。假设用户如今在第5页,页面大小为3,那么页面的最小值为20-3*5+1=6,页面最大值为6+3-1=8。若是如今用户想去第2页,第二页的页面最小值为20-2*3+1=15,页面最大值为15+3-1=17。那么sql就很容易能够写来。

第一步获取总数【select count(*) from t1;】

第二步执行需求页面的查询【select * from t1 where id<=17 and id>=15 order by id desc limit 3;】

固然也能够写成一个嵌套子查询。

5.一些困惑

当用户在跳页查询的时候有数据插入咋办?直接进行锁表吗。

若是id不是连续而是中间有缺值呢?不少网站是没有提供跳页功能,可是应该有更高级的方法来实现,好比创建复杂的数据结构来维护之类的。