Mysql中分页查询的两个解决方法比较


Posted in PHP onMay 02, 2013

mysql中分页查询有两种方式, 一种是使用COUNT(*)的方式,具体代码如下

SELECT COUNT(*) FROM foo WHERE b = 1; 
SELECT a FROM foo WHERE b = 1 LIMIT 100,10;

另外一种是使用SQL_CALC_FOUND_ROWS
SELECT SQL_CALC_FOUND_ROWS a FROM foo WHERE b = 1 LIMIT 100, 10; 
SELECT FOUND_ROWS();

第二种方式调用SQL_CALC_FOUND_ROWS之后会将WHERE语句查询的行数放在FOUND_ROWS()之中,第二次只需要查询FOUND_ROWS()就可以查出有多少行了。

讨论这两种方法的优缺点:
首先原子性讲,第二种肯定比第一种好。第二种能保证查询语句的原子性,第一种当两个请求之间有额外的操作修改了表的时候,结果就自然是不准确的了。而第二种则不会。但是非常可惜,一般页面需要进行分页显示的时候,往往并不要求分页的结果非常准确。即分页返回的total总数大1或者小1都是无所谓的。所以其实原子性不是我们分页关注的重点。

下面看效率。这个非常重要,分页操作在每个网站上的使用都是非常大的,查询量自然也很大。由于无论哪种,分页操作必然会有两次sql查询,于是就有很多很多关于两种查询性能的比较:

SQL_CALC_FOUND_ROWS真的很慢么?

http://hi.baidu.com/thinkinginlamp/item/b122fdaea5ba23f614329b14

To SQL_CALC_FOUND_ROWS or not to SQL_CALC_FOUND_ROWS?

http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

老王这篇文章里面有提到一个covering index的概念,简单来说就是怎样才能只让查询根据索引返回结果,而不进行表查询

具体看他的另外一篇文章:

MySQL之Covering Index

http://hi.baidu.com/thinkinginlamp/item/1b9aaf09014acce0f45ba6d3

实验
结合这几篇文章,做的实验:

表:

CREATE TABLE IF NOT EXISTS `foo` ( 
`a` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`b` int(10) unsigned NOT NULL, 
`c` varchar(100) NOT NULL, 
PRIMARY KEY (`a`), 
KEY `bar` (`b`,`a`) 
) ENGINE=MyISAM;

注意下这里是使用b,a做了一个索引,所以查询select * 的时候是不会用到covering index的,select a才会使用到covering index
<?php $host = '192.168.100.166'; 
$dbName = 'test'; 
$user = 'root'; 
$password = ''; 
$db = mysql_connect($host, $user, $password) or die('DB connect failed'); 
mysql_select_db($dbName, $db); 
  
echo '==========================================' . "\r\n"; 
$start = microtime(true); 
for ($i =0; $i<1000; $i++) { 
    mysql_query("SELECT SQL_NO_CACHE COUNT(*) FROM foo WHERE b = 1"); 
    mysql_query("SELECT SQL_NO_CACHE a FROM foo WHERE b = 1 LIMIT 100,10"); 
} 
$end = microtime(true); 
echo $end - $start . "\r\n"; 
echo '==========================================' . "\r\n"; 
$start = microtime(true); 
for ($i =0; $i<1000; $i++) { 
    mysql_query("SELECT SQL_NO_CACHE SQL_CALC_FOUND_ROWS a FROM foo WHERE b = 1 LIMIT 100, 10"); 
    mysql_query("SELECT FOUND_ROWS()"); 
} 
$end = microtime(true); 
echo $end - $start . "\r\n"; 
echo '==========================================' . "\r\n"; 
$start = microtime(true); 
for ($i =0; $i<1000; $i++) { 
    mysql_query("SELECT SQL_NO_CACHE COUNT(*) FROM foo WHERE b = 1"); 
    mysql_query("SELECT SQL_NO_CACHE * FROM foo WHERE b = 1 LIMIT 100,10"); 
} 
$end = microtime(true); 
echo $end - $start . "\r\n"; 
echo '==========================================' . "\r\n"; 
$start = microtime(true); 
for ($i =0; $i<1000; $i++) { 
    mysql_query("SELECT SQL_NO_CACHE SQL_CALC_FOUND_ROWS * FROM foo WHERE b = 1 LIMIT 100, 10"); 
    mysql_query("SELECT FOUND_ROWS()"); 
} 
$end = microtime(true); 
echo $end - $start . "\r\n";

返回的结果:
Mysql中分页查询的两个解决方法比较
和老王里面文章说的是一样的。第四次查询SQL_CALC_FOUND_ROWS由于不仅是没有使用到covering index,也需要进行全表查询,而第三次查询COUNT(*),且select * 有使用到index,并没进行全表查询,所以有这么大的差别。

总结
PS: 另外提醒下,这里是使用MyISAM会出现三和四的查询差别这么大,但是如果是使用InnoDB的话,就不会有这么大差别了。

所以我得出的结论是如果数据库是InnoDB的话,我还是倾向于使用SQL_CALC_FOUND_ROWS

结论:SQL_CALC_FOUND_ROWS和COUNT(*)的性能在都使用covering index的情况下前者高,在没使用covering index情况下后者性能高。所以使用的时候要注意这个。

PHP 相关文章推荐
PHP数据库开发知多少
Oct 09 PHP
图象函数中的中文显示
Oct 09 PHP
以文本方式上传二进制文件的PHP程序
Oct 09 PHP
用PHP和ACCESS写聊天室(七)
Oct 09 PHP
php select,radio和checkbox默认选择的实现方法
May 15 PHP
php curl的深入解析
Jun 02 PHP
PHP中COOKIES使用示例
Jul 26 PHP
windows下apache搭建php开发环境
Aug 27 PHP
谈谈你对Zend SAPIs(Zend SAPI Internals)的理解
Nov 10 PHP
PHP获取文件扩展名的4种方法
Nov 24 PHP
PHP编程计算文件或数组中单词出现频率的方法
May 22 PHP
Thinkphp 框架扩展之行为扩展原理与实现方法分析
Apr 23 PHP
记录mysql性能查询过程的使用方法
May 02 #PHP
基于MySQL分区性能的详细介绍
May 02 #PHP
php中使用$_REQUEST需要注意的一个问题
May 02 #PHP
PHP执行批量mysql语句的解决方法
May 02 #PHP
PHP闭包(Closure)使用详解
May 02 #PHP
PHP5中Cookie与 Session使用详解
Apr 30 #PHP
PHP容易忘记的知识点分享
Apr 30 #PHP
You might like
东芝TOSHIBA RP-F11电路分析
2021/03/02 无线电
php操作xml
2013/10/27 PHP
PHP获取文件相对路径的方法
2015/02/26 PHP
php进行ip地址掩码运算处理的方法
2016/07/11 PHP
php多线程并发实现方法
2016/09/30 PHP
js 目录列举函数
2008/11/06 Javascript
js表格分页实现代码
2009/09/18 Javascript
js Html结构转字符串形式显示代码
2011/11/15 Javascript
JQuery.closest(),parent(),parents()寻找父结点
2012/02/17 Javascript
JavaScript中的条件判断语句使用详解
2015/06/03 Javascript
javascript实现类似于新浪微博搜索框弹出效果的方法
2015/07/27 Javascript
BootStrap实现树形目录组件代码详解
2016/06/21 Javascript
bootstrap模态框消失问题的解决方法
2016/12/02 Javascript
Vue form 表单提交+ajax异步请求+分页效果
2017/04/22 Javascript
JS正则表达式验证中文字符
2017/05/08 Javascript
vue多页面开发和打包正确处理方法
2018/04/20 Javascript
vue项目中仿element-ui弹框效果的实例代码
2019/04/22 Javascript
微信小程序 腾讯地图显示偏差问题解决
2019/07/27 Javascript
微信小程序实现比较功能的方法汇总(五种方法)
2020/03/07 Javascript
javascript前端实现多视频上传
2020/12/13 Javascript
python的tkinter布局之简单的聊天窗口实现方法
2014/09/03 Python
在Debian下配置Python+Django+Nginx+uWSGI+MySQL的教程
2015/04/25 Python
python 计算两个日期相差多少个月实例代码
2017/05/24 Python
python实现感知器
2017/12/19 Python
Python实现二叉树的最小深度的两种方法
2019/09/30 Python
10分钟理解CSS3 FlexBox弹性布局
2018/12/20 HTML / CSS
css3动画 小球滚动 js控制动画暂停
2019/11/29 HTML / CSS
联想法国官方网站:Lenovo法国
2018/10/18 全球购物
幼儿园家长会欢迎词
2014/01/09 职场文书
学生干部学习的自我评价
2014/02/18 职场文书
文明班级建设方案
2014/05/15 职场文书
大学生就业推荐表自我评价
2015/03/02 职场文书
违规违纪检讨书范文
2015/05/06 职场文书
上甘岭观后感
2015/06/10 职场文书
少儿励志名言(80句)
2019/08/14 职场文书
深入理解margin塌陷和margin合并的解决方案
2021/06/26 HTML / CSS