欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MySQL高效分页解决方案集分享

程序员文章站 2024-02-27 15:45:33
一,最常见mysql最基本的分页方式:复制代码 代码如下:select * from content order by id desc limit 0, 10在中小数据量的...
一,最常见mysql最基本的分页方式:
复制代码 代码如下:

select * from content order by id desc limit 0, 10

在中小数据量的情况下,这样的sql足够用了,唯一需要注意的问题就是确保使用了索引。随着数据量的增加,页数会越来越多,查看后几页的sql就可能类似:
复制代码 代码如下:

select * from content order by id desc limit 10000, 10

一言以蔽之,就是越往后分页,limit语句的偏移量就会越大,速度也会明显变慢。
此时,我们可以通过2种方式:
一,子查询的分页方式来提高分页效率,飘易用的sql语句如下:
复制代码 代码如下:

select * from `content` where id (select id from `content` order by id desc limit ".($page-1)*$pagesize.", 1) order by id desc limit $pagesize

为什么会这样呢?因为子查询是在索引上完成的,而普通的查询时在数据文件上完成的,通常来说,索引文件要比数据文件小得多,所以操作起来也会更有效率。(via)通过explain sql语句发现:子查询使用了索引!
复制代码 代码如下:

id select_type table type possible_keys key key_len ref rows extra
1 primary content range primary primary 4 null 6264 using where
2 subquery content index null primary 4 null 27085 using index

经过飘易的实测,使用子查询的分页方式的效率比纯limit提高了14-20倍!
二,join分页方式
复制代码 代码如下:

select * from `content` as t1
join (select id from `content` order by id desc limit ".($page-1)*$pagesize.", 1) as t2
where t1.id

经过我的测试,join分页和子查询分页的效率基本在一个等级上,消耗的时间也基本一致。explain sql语句:
复制代码 代码如下:

id select_type table type possible_keys key key_len ref rows extra
1 primary system null null null null 1
1 primary t1 range primary primary 4 null 6264 using where
2 derived content index null primary 4 null 27085 using index

三,使用mysql的found_rows()函数
mysql found_rows() 函数结合sql_calc_found_rows在select中可以得到两个结果:
1. 得到limit的内容
2. 得到去除limit以后所有行数
select语句中经常可能用limit限制返回行数。有时候可能想要知道如果没有limit会返回多少行,但又不想再执行一次相同语句。那么,在select查询中包含sql_calc_found_rows选项,然后执行found_rows()就可以了:
复制代码 代码如下:

select sql_calc_found_rows * from tbl_name where id > 100 limit 10;
select found_rows();

其中sql_calc_found_rows 告诉mysql将sql所处理的行数记录下来,found_rows() 则取到了这个纪录。 虽然也是两个语句,但是只执行了一次主查询,所以效率比原来要高很多。
1. 如果在前一条语句中使用sql_calc_found_rows选项,found_rows()将返回第一条语句没有limit时返回的行数。
2. 如果在前一条语句中没有使用sql_calc_found_rows选项,found_rows()将返回前一条语句实际返回的行数。
如果使用 select sql_calc_found_rows,mysql必须计算所有结果集的行数。尽管这样,总比再执行一次不使用limit的查询要快多了吧,因为那样结果集要返回客户端滴。(另外:应该不单是没有将结果集返回的原因,还有原因可能是比如like之类比较费劲的sql不需要再去劳累一次。)
复制代码 代码如下:

-- 注意下面语句中的条件 like
select sql_calc_found_rows * from tbl_name where name like '%string%' id > 100 limit 10;
select found_rows();

复制代码 代码如下:

-- 上面语句等价于下面语句,但性能方面应该提升非常非常的明显:
select count(*) from tbl_name where name like '%string%' ;
select * from tbl_name where name like '%string%' id > 100 limit 10;