mysql中关于SQL_CALC_FOUND_ROWS的使用与否

最近在代码中发现了这个mysql关键字 SQL_CALC_FOUND_ROWS

代码中是这么写的:

$dbProxy = self::getDBProxy();
$sql = "SELECT SQL_CALC_FOUND_ROWS * FROM rl_item_img_relation WHERE img_id=$id  limit 0,100 ";
$ret = $dbProxy->rs2array($sql);
$count = $dbProxy->rs2foundrows();

用处自然是无需在写一个count(img_id) ,省了一个方法,那么性能如何呢?

这里找到老外的一篇文章(http://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/),自己动手试下,眼见为实嘛!

mysql> CREATE TABLE `count_test` (
    ->   `a` int(10) NOT NULL auto_increment,
    ->   `b` int(10) NOT NULL,
    ->   `c` int(10) NOT NULL,
    ->   `d` varchar(32) NOT NULL,
    ->   PRIMARY KEY  (`a`),
    ->   KEY `bc` (`b`,`c`)
    -> ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.01 sec)
<?php
mysql_connect("127.0.0.1", "root");
mysql_select_db("test");
for ($i = 0; $i < 10000000; $i++) {
    $b = $i % 1000;
    mysql_query("INSERT INTO count_test SET b=$b, c=ROUND(RAND()*10), d=MD5($i)");
}

我这里先是导入了大约124万,下面来查询下:

mysql> SELECT SQL_NO_CACHE * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+-------+-----+---+----------------------------------+
| a     | b   | c | d                                |
+-------+-----+---+----------------------------------+
| 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
+-------+-----+---+----------------------------------+
1 row in set (0.01 sec)

mysql> SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+----------+
| count(*) |
+----------+
|     1247 |
+----------+
1 row in set (0.00 sec)

mysql> SELECT SQL_NO_CACHE   SQL_CALC_FOUND_ROWS  * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+-------+-----+---+----------------------------------+
| a     | b   | c | d                                |
+-------+-----+---+----------------------------------+
| 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
+-------+-----+---+----------------------------------+
1 row in set (0.01 sec)

两条分开的语句和合并一起的貌似没有什么差距。继续导入数据到千万级数据看下:

mysql> SELECT SQL_NO_CACHE   SQL_CALC_FOUND_ROWS  * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+-------+-----+---+----------------------------------+
| a     | b   | c | d                                |
+-------+-----+---+----------------------------------+
| 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
+-------+-----+---+----------------------------------+
1 row in set (45.14 sec)

mysql> SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+----------+
| count(*) |
+----------+
|    11247 |
+----------+
1 row in set (0.01 sec)

mysql> SELECT SQL_NO_CACHE * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+-------+-----+---+----------------------------------+
| a     | b   | c | d                                |
+-------+-----+---+----------------------------------+
| 18556 | 555 | 0 | 07895306ffe62e559d2cff903c91e66b |
+-------+-----+---+----------------------------------+
1 row in set (0.00 sec)

差距出来了,为什么?

看看sql语句的explain

mysql> explain SELECT SQL_NO_CACHE   SQL_CALC_FOUND_ROWS  * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
|  1 | SIMPLE      | count_test | ref  | bc            | bc   | 4       | const | 11431 | Using where |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
1 row in set (0.00 sec)
mysql> explain   SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
|  1 | SIMPLE      | count_test | ref  | bc            | bc   | 4       | const | 11431 | Using index |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
1 row in set (0.00 sec)

mysql> explain SELECT SQL_NO_CACHE * FROM count_test WHERE b = 555 ORDER BY c LIMIT 1;
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
| id | select_type | table      | type | possible_keys | key  | key_len | ref   | rows  | Extra       |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
|  1 | SIMPLE      | count_test | ref  | bc            | bc   | 4       | const | 11431 | Using where |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
1 row in set (0.00 sec)

原博只是比对了后两条语句,没有进行第一条语句的比较,直接得出了结论,但是如果加上第一条语句的话,还是无法解释上述的查询的时间差距,原博得出这个结论是片面的。

根据mysql 官方手册(http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_found-rows)描述:

     If you are using SELECT SQL_CALC_FOUND_ROWS, MySQL must calculate how many rows are in the full result set. 
However, this is faster than running the query again without LIMIT, because the result set need not be sent 
to the client.

   SQL_CALC_FOUND_ROWS and FOUND_ROWS() can be useful in situations when you want to restrict the number of rows
 that a query returns, but also determine the number of rows in the full result set without running the query again.
 An example is a Web script that presents a paged display containing links to the pages that show other sections of 
a search result. Using FOUND_ROWS() enables you to determine how many other pages are needed for the rest of the 
result.

按照手册说法,SQL_CALC_FOUND_ROWS 和 FOUND_ROWS()是被推荐使用的,至少比再查询一次快。就像原博评论里说的,我们没有理由不相信官方手册啊!

时间: 2024-10-07 12:32:11

mysql中关于SQL_CALC_FOUND_ROWS的使用与否的相关文章

MySQL中SQL_CALC_FOUND_ROWS的用法

1. SQL_CALC_FOUND_ROWS简述 在很多分页的程序中都这样写: #查出符合条件的记录总数 SELECT COUNT(*) from [table] WHERE ......; #查询当页要显示的数据 SELECT * FROM [table] WHERE ...... limit M,N; 但是从Mysql4.0.0开始,我们可以选择使用另外一个方式: SELECT SQL_CALC_FOUND_ROWS * FROM [table] WHERE ...... limit M,

mysql中的保留字段,说多了都是泪啊!!!!

前几天因为功能的临时变更,需要给数据表添加一个字段用来区别导入的批次,我就在mysql中添加了group字段,没想到我的噩梦就此展开····· 本来程序已经接近收尾,本想着今早来公司给程序来个欢乐的结尾,没想到····每次导入excel表总是提示我sql语句错误,我变在sql语句上添添减减,也没有把错误搞定,整整一个上午外加下午两个小时,简直已经到了抓狂的程度.简直要跪地苦思冥想,但是还是没有搞定这个错误. 把问题放在一边,继续搞其他的东西····当在写一个group by 语句时,突然意识到,

MySQL 中的 FOUND_ROWS() 函数

移植sql server 的存储过程到mysql中,遇到了sql server中的: IF @@ROWCOUNT < 1 对应到mysql中可以使用 FOUND_ROWS() 函数来替换. 1. found_rows() 函数的文档: http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_found-rows 1)found_rows() 的第一种使用情况(带有SQL_CALC_FOUND_ROWS,

【个人笔记】《知了堂》MySQL中的数据类型

MySQL中的数据类型 1.整型 MySQL数据类型 含义(有符号) tinyint(m) 1个字节  范围(-128~127) smallint(m) 2个字节  范围(-32768~32767) mediumint(m) 3个字节  范围(-8388608~8388607) int(m) 4个字节  范围(-2147483648~2147483647) bigint(m) 8个字节  范围(+-9.22*10的18次方) 取值范围如果加了unsigned,则最大值翻倍,如tinyint un

mysql中int、bigint、smallint和tinyint的区别与长度

对比发现 int bigint smallint 和 tinyint 类型,如果创建新表时没有指定 int(M) 中的M时,默认分别是 : int             -------     int(11) bigint       -------     bigint(20) smallint   -------     smallint(6) tinyint     -------     tinyint(4) 下面是这几种类型的取值范围 参考:http://www.2cto.com/d

mysql中计算两个日期的时间差函数TIMESTAMPDIFF用法

mysql中计算两个日期的时间差函数TIMESTAMPDIFF用法: 语法: TIMESTAMPDIFF(interval,datetime_expr1,datetime_expr2) 说明: 返回日期或日期时间表达式datetime_expr1 和datetime_expr2the 之间的整数差.其结果的单位由interval 参数给出.interval 的法定值同TIMESTAMPADD()函数说明中所列出的相同. mysql> SELECT TIMESTAMPDIFF(MONTH,'200

SQL-GROUP BY语句在MySQL中的一个错误使用被兼容的情况

首先创建数据库hncu,建立stud表格. 添加数据: create table stud( sno varchar(30) not null primary key, sname varchar(30) not null, age int, saddress varchar(30) ); INSERT INTO stud VALUES('1001','Tom',22,'湖南益阳'); INSERT INTO stud VALUES('1002','Jack',23,'益阳'); INSERT

MYSQL中存储过程的创建,调用及语法

MySQL 存储过程是从 MySQL 5.0 开始增加的新功能.存储过程的优点有一箩筐.不过最主要的还是执行效率和SQL 代码封装.特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库时(例如 PHP),要组织很多 SQL 语句.特别是业务逻辑复杂的时候,一大堆的 SQL 和条件夹杂在 PHP 代码中,让人不寒而栗.现在有了 MySQL 存储过程,业务逻辑可以封装存储过程中,这样不仅容易维护,而且执行效率也高. 第一部分:创建一个简单的无参的存储过程 1 用mysql客户端登入

在Mysql中如何显示所有用户?

在Mysql中如何显示所有用户? 这是一个mysql初学者经常问到的一个问题,今天我们就带大家看看是如何在Mysql中显示所有用户的.通常我们在mysql中使用SHOW DATABASES可以显示所有的数据库,SHOW TABLES将会显示所有的数据表,那么你是不是会猜测显示所有用户的命令是SHOW USERS呢?不不不,并不是的,现在让我们一起来看看如何显示所有用户吧. 在Mysql中显示所有用户 1.登录数据库 首先,你需要使用如下命令登录到数据库,注意,必须是root用户哦~ ## mys