T086学习网 | 站长学院 | 技术文档 | 成语 | 歇后语 | 帝国时代 | 代码收藏 | IP地址查询 | 生活百科 | 生日密码 | CSS压缩 | 用户评论 | 欣欣百宝箱

SQL_CALC_FOUND_ROWS真的很慢么?

【 作者:老王 更新时间:2012-05-17 | 字体:
[导读]分页程序一般由两条SQL组成: SELECT COUNT(*) FROM ... WHERE .... SELECT ... FROM ... WHERE LIMIT ... 如果使用SQL_CALC_FOUND_ROWS的话,一条SQL就可以了: SELECT SQL_CALC_FOUND_ROWS ... FROM ... WHERE LIM...

分页程序一般由两条SQL组成:

SELECT COUNT(*) FROM ... WHERE ....
SELECT ... FROM ... WHERE LIMIT ...


如果使用SQL_CALC_FOUND_ROWS的话,一条SQL就可以了:

SELECT SQL_CALC_FOUND_ROWS ... FROM ... WHERE LIMIT ...

在得到数据后,通过FOUND_ROWS()可以得到不带LIMIT的结果数:

SELECT FOUND_ROWS()

看上去,似乎SQL_CALC_FOUND_ROWS应该快于COUNT(*),但实际情况并不是这样简单,请看:

To SQL_CALC_FOUND_ROWS or not to SQL_CALC_FOUND_ROWS?

用数据说话,证明了COUNT(*)相对SQL_CALC_FOUND_ROWS来说更快。

不过我觉得这个结论也不全面,某些情况下,SQL_CALC_FOUND_ROWS更有优势,看我的实验:

表结构如下:

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;


导入一些测试数据:

for ($i = 0; $i <10000; $i++) {
mysql_query("INSERT INTO foo SET b=ROUND(RAND()*10), c=MD5({$i})");
}


先测试COUNT(*)方式:

$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;


结果输出(数据大小视测试机性能而定):0.75777006149292

再测试SQL_CALC_FOUND_ROWS方式:

$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;


结果输出(数据大小视测试机性能而定):0.6681969165802

有数据有真相,那为什么我的实验结论和MySQL Performance Blog的结论相悖呢?这是因为:

在MySQL Performance Blog的实验里,COUNT(*)查询是执行的的Covering Index,而SQL_CALC_FOUND_ROWS是执行的表查询;而在我的实验里,因为我定义了适当的索引,COUNT(*)和SQL_CALC_FOUND_ROWS都是执行的Covering Index,所以结论出现了差异。

既然使用了Covering Index,就意味着不能再使用SELECT *的形式了,只能使用类似SELECT id这样的形式了,用的列在索引里都能查到,如此说来,我们需要的实际数据从哪来呢?这个很简单,有了主键之后,实际数据可以通过Key/Value形式的缓存获得,这样的架构很常见。

结论:SQL_CALC_FOUND_ROWS如果执行的是Covering Index的话,是很快的!换个角度看,如果COUNT(*)和SQL_CALC_FOUND_ROWS都只能通过表查询来检索,那么分页时,SQL_CALC_FOUND_ROWS同样会快于COUNT(*),读者可自行测试。

补充:Fast paging in the real world

原文:http://hi.baidu.com/thinkinginlamp/blog/item/df85b31c93cd148686d6b64f.html

  • 转载请注明来源:IT学习网 网址:http://www.t086.com/ 向您的朋友推荐此文章
  • 特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系我们,我们会尽快予以更正。
更多
留言建议ASP探针PHP探针站长Enjoy的Blog
© 2017 T086学习网 - T086.com(原itlearner.com)
RunTime:7.89ms QueryTime:7