When we optimize clients’ SQL queries I pretty often see a queries with SQL_CALC_FOUND_ROWS option used. Many people think, that it is faster to use this option than run two separate queries: one – to get a result set, another – to count total number of rows.
In this post I’ll try to check, is this true or not and when it is better to run two separate queries.
tudou@Gyyx
当我们优化客户端SQL查询时,我经常看到使用SQL_CALC_FOUND_ROWS选项的查询.很多人认为,使用此选项要比运行两个单独的查询速度更快:第一条SQL获取结果集,第二条获取全集的总数(分页中我们经常这样使用).在这篇文章中我将检验使用SQL_CALC_FOUND_ROWS是否比运行两个单独的查询更好.
For my tests I’ve created following simple table:
创建示例表:
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
Test data has been created with following script (which creates 10M records):
向示例表中插入1000W行数据:
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)");
}
First of all, let's try to perform some query on this table using indexed columnbin where clause:
首先,我们尝试一条使用了索引b的查询
mysql> SELECT SQL_NO_CACHE SQL_CALC_FOUND_ROWS * FROM count_test WHERE b = 555 ORDER BY c LIMIT 5;
Results with SQL_CALC_FOUND_ROWS are following: for eachbvalue it takes 20-100 sec to execute uncached and 2-5 sec after warmup. Such difference could be explained by the I/O which required for this query - mysql accesses all 10k rows this
query could produce without LIMIT clause.
使用SQL_CALC_FOUND_ROWS的结果如下:每个b列中的值需要20-100秒左右来加载到内存中,然后运算2-5秒得到结果.这和不使用LIMIT子句查询1W行数据的I/O消耗相当.
Let's check, how long it'd take if we'll try to use two separate queries:
我们再来检验下使用两条SQL语句的时长:
mysql> SELECT SQL_NO_CACHE * FROM count_test WHERE b = 666 ORDER BY c LIMIT 5;
The results are following: it takes 0.01-0.11 sec to run this query first time and 0.00-0.02 sec for all consecutive runs.
结果如下:第一次执行需要0.01-.011秒,其后相同的查询只须0.00-0.02秒(因为与此查询相关的索引被加载到了内存中,加快了数据的检索).
And now - we need too check how long our COUNT query would take:
接下来我们还需检验下执行COUNT查询的时长:
mysql> SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 666;
Result is really impressive here: 0.00-0.04 sec for all runs.
结果很棒:只须0.00-0.04秒.
So, as we can see, total time for SELECT+COUNT (0.00-0.15 sec) is much less than execution time for original query (2-100 sec). Let's take a look at EXPLAINs
因此,我们可以看到,对于SELECT+ COUNT(0.00-0.15秒)的总时间比使用SQL_CALC_FOUND_ROWS的查询(2-100秒)的执行时间少得多。让我们来看看EXPLAIN的情况:
mysql> explain SELECT SQL_CALC_FOUND_ROWS * FROM count_test WHERE b = 999 ORDER BY c LIMIT 5;
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
| 1 | SIMPLE | count_test | ref | bc | bc | 4 | const | 75327 | Using where |
+----+-------------+------------+------+---------------+------+---------+-------+-------+-------------+
1 row in set (0.00 sec)
mysql> explain SELECT SQL_NO_CACHE count(*) FROM count_test WHERE b = 666;
+----+-------------+------------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | count_test | ref | bc | bc | 4 | const | 5479 | Using index |
+----+-------------+------------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
Here is why our count was much faster - MySQL accessed our table data when calculated result set size even when this was not needed (after the first 5 rows specified in LIMIT clause). With count(*) it used index scan inly which is much faster here.
这就是为什么使用COUNT如此快速:MySQL计算结果集大小时甚至访问了这条语句并不需要的数据(包括那些不在LIMIT 5 范围内的数据).
Just to be objective I've tried to perform this test without indexes (full scan) and with index onbcolumn. Results were following:
为了更加客观,我试着测试没有索引(全扫描)和B列的索引。结果如下:
-
Full-scan:
-
7 seconds for SQL_CALC_FOUND_ROWS.
-
7+7 seconds in case when two queries used.
-
Filesort:
-
1.8 seconds for SQL_CALC_FOUND_ROWS.
-
1.8+0.05 seconds in case when two queries used.
So, obvious conclusion from this simple test is: when we have appropriate indexes for WHERE/ORDER clause in our query, it is much faster to use two separate queries instead of one with SQL_CALC_FOUND_ROWS.
因此,这个测试的结论是:当我们有适当的索引可以应用时,应当使用两个单独的查询,这要比SQL_CALC_FOUND_ROWS快得多。
原文链接:http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
分享到:
相关推荐
那么,在SELECT查询中包含SQL_CALC_FOUND_ROWS选项,然后执行FOUND_ROWS()就可以了:代码如下mysql> SELECT SQL_
mysql的SQL_CALC_FOUND_ROWS 使用 获取查询的行数 在很多分页的程序中都这样写: 代码如下 SELECT COUNT(*) from `table` WHERE ……; 查出符合条件的记录总数 代码如下 SELECT * FROM `table` WHERE …… limit M,N;...
mysql中分页查询有两种方式, 一种是使用COUNT(*)的方式,具体代码如下 复制代码 代码如下:SELECT COUNT(*) FROM foo WHERE b = 1; SELECT a FROM foo WHERE b = 1 LIMIT 100,10; 另外一种是使用SQL_CALC_FOUND_ROWS ...
MYSQL的关键词 : SQL_CALC_FOUND_ROWS 查看手册后发现此关键词的作用是在查询时统计满足过滤条件后的结果的总数(不受 Limit 的限制) 例如: 代码如下: SELECT SQL_CALC_FOUND_ROWS tid FROM cdb_threads WHERE fid...
SELECT SQL_CALC_FOUND_ROWS wp_posts . ID FROM wp_posts WHERE 1 = 1 AND wp_posts . post_type = ' post ' AND ( wp_posts . post_status = ' publish ' ) ORDER BY wp_posts . post_date DESC LIMIT 0 , 10 ; ...
mysql中可以使用SQL_CALC_FOUND_ROWS来获取查询的行数,在很多分页的程序中都这样写: 代码如下:SELECT COUNT(*) from `table` WHERE ……; 查出符合条件的记录总数: 代码如下:SELECT * FROM `table` WHERE …… ...
SELECT SQL_CALC_FOUND_ROWS * FROM TABLE WHERE 1=1; 即可得出总数据行数 SET @RowCount=found_rows(); 三、存储过程数据查询分页 预定义变量: /*错误代码*/ SET @RetCode='1'; /*错误提示*/ SET @
6.7.6优化SQL_CALC_FOUND_ROWS243 6.7.7优化UNION查询243 6.7.8静态查询分析244 6.7.9使用用户自定义变量244 6.8案例学习251 6.8.1使用MySQL构建一个队列表251 6.8.2计算两点之间的距离254 6.8.3使用用户...
Syntax: SELECT [ALL | DISTINCT | DISTINCTROW ] [HIGH_PRIORITY] [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] select_expr [, ...
CHAPTER 1 Introduction to MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Database, ...
奇虎360公司开源的... 解决SQL_CALC_FOUND_ROWS之后SQL语句发往主库的问题 解决SQL语句中有注释时语句分析不正确的问题 解决客户端发送空串导致DBProxy挂掉的问题 标签:meituan
--(函数to-date 查询公司在所给时间以后入职的人员) 43、select sal from emp where sal > to_number('$1,250.00', '$9,999.99'); --(函数to_number()求出这种薪水里带有特殊符号的) 44、select ename, sal*12 ...
New : Autosizing columns / rows on double-click in TTMSFMXGrid New : Column persistence in TTMSFMXGrid Improved : Data reset when toggling active in TTMSFMXScope Fixed : Issue with checkbox and ...
:glowing_star: 特征制表器的功能: Filters Sorting Formatting Grouping Ajax Editing Virtualization Pagination Themes A11y I18n Layouts Frozen Cols/Rows Key Binding Responsive Persisting History Calc ...
<END><br>28 , calc.zip This is a basic calculator written in Visual Basic.<END><br>29 , stopwatch.zip This shows how to count off time in a Stop Watch format.<END><br>31 , taskhide.zip This ...
<textarea name="mbox" cols="80" rows="10"> </center></td> <td width="9%" height="30"><center> ()" NAME="Button1"> <INPUT TYPE=button VALUE="GetCPU_ID" ONCLICK="GetCPU_ID()" NAME="Button2...