MySQL分页的同时查询记录总数 SQL_CALC_FOUND_ROWS的性能测试

select * from auth_user

SELECT FOUND_ROWS() //返回查询记录的总数

select sql_calc_found_rows col_name from table_name limit 5,3;
select found_rows()


SELECT语句中加上修饰SQL_CALC_FOUND_ROWS

加上SQL_CALC_FOUND_ROWS之后,即使你用了limit n,m ,SELECT FOUND_ROWS() 仍会返回满足条件记录的总数。这样,你执行完 select SQL_CALC_FOUND_ROWS 之后,再取一下记录总数就行了。


分页程序一般由两条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(*),读者可自行测试。

注:http://kb.cnblogs.com/page/82986/

你可能感兴趣的:(数据库)