MySQL高效分页解决方案集

好久之前的一次面试中,被面试官问到这个问题,因为平时用到的分页方法很少,只从索引、分表、使用子查询精准定位偏移之外,没有使用到其它方法。
后来在看其它博客看到了一些不一样的方案,也一直没有整理。今天有时间,整理出来,分享给你们。php

一,最多见MYSQL最基本的分页方式:html

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

在中小数据量的状况下,这样的SQL足够用了,惟一须要注意的问题就是确保使用了索引。随着数据量的增长,页数会愈来愈多,查看后几页的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语句发现:子查询使用了索引!spa

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 indexorm

通过飘易的实测,使用子查询的分页方式的效率比纯LIMIT提升了14-20倍!
二,JOIN分页方式htm

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;

参考博客:http://blog.hexu.org/archives/1328.shtmlhttp://hi.baidu.com/thinkinginlamp/blog/item/17476d22d66876a14623e81d.htmlhttp://www.piaoyi.org/php/MySQL-SUBQUERY-index.html

相关文章
相关标签/搜索