`
java-mans
  • 浏览: 11439989 次
文章分类
社区版块
存档分类
最新评论

MySQL 分页查询: To SQL_CALC_FOUND_ROWS or not to SQL_CALC_FOUND_ROWS?

 
阅读更多

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列的索引。结果如下:

  1. Full-scan:
    • 7 seconds for SQL_CALC_FOUND_ROWS.
    • 7+7 seconds in case when two queries used.
  2. 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/

分享到:
评论

相关推荐

    mysql SELECT FOUND_ROWS()与COUNT()用法区别1

    那么,在SELECT查询中包含SQL_CALC_FOUND_ROWS选项,然后执行FOUND_ROWS()就可以了:代码如下mysql&gt; SELECT SQL_

    mysql获取group by的总记录行数另类方法

    mysql的SQL_CALC_FOUND_ROWS 使用 获取查询的行数 在很多分页的程序中都这样写: 代码如下 SELECT COUNT(*) from `table` WHERE ……; 查出符合条件的记录总数 代码如下 SELECT * FROM `table` WHERE …… limit M,N;...

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

    mysql中分页查询有两种方式, 一种是使用COUNT(*)的方式,具体代码如下 复制代码 代码如下:SELECT COUNT(*) FROM foo WHERE b = 1; SELECT a FROM foo WHERE b = 1 LIMIT 100,10; 另外一种是使用SQL_CALC_FOUND_ROWS ...

    MYSQL中统计查询结果总行数的便捷方法省去count(*)

    MYSQL的关键词 : SQL_CALC_FOUND_ROWS 查看手册后发现此关键词的作用是在查询时统计满足过滤条件后的结果的总数(不受 Limit 的限制) 例如: 代码如下: SELECT SQL_CALC_FOUND_ROWS tid FROM cdb_threads WHERE fid...

    fast-wp-query:WP_Query通过使用对象缓存进行MySQL优化

    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获取group by总记录行数的方法

    mysql中可以使用SQL_CALC_FOUND_ROWS来获取查询的行数,在很多分页的程序中都这样写: 代码如下:SELECT COUNT(*) from `table` WHERE ……; 查出符合条件的记录总数: 代码如下:SELECT * FROM `table` WHERE …… ...

    MySQL数据库常用操作技巧总结

    SELECT SQL_CALC_FOUND_ROWS * FROM TABLE WHERE 1=1; 即可得出总数据行数 SET @RowCount=found_rows(); 三、存储过程数据查询分页 预定义变量: /*错误代码*/ SET @RetCode='1'; /*错误提示*/ SET @

    高性能MySQL(第3版).part2

    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使用用户...

    mysql语言之SELECT

    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 [, ...

    Sql for mysql

    CHAPTER 1 Introduction to MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Database, ...

    基于MySQL的数据库中间件Meituan-DBProxy.zip

    奇虎360公司开源的... 解决SQL_CALC_FOUND_ROWS之后SQL语句发往主库的问题 解决SQL语句中有注释时语句分析不正确的问题 解决客户端发送空串导致DBProxy挂掉的问题 标签:meituan

    精髓Oralcle讲课笔记

    --(函数to-date 查询公司在所给时间以后入职的人员) 43、select sal from emp where sal &gt; to_number('$1,250.00', '$9,999.99'); --(函数to_number()求出这种薪水里带有特殊符号的) 44、select ename, sal*12 ...

    TMS Pack for FireMonkey2.3.0.1

    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 ...

    react-tabulator:React Tabulator基于Tabulator-一个具有许多高级功能的JS表库

    :glowing_star: 特征制表器的功能: Filters Sorting Formatting Grouping Ajax Editing Virtualization Pagination Themes A11y I18n Layouts Frozen Cols/Rows Key Binding Responsive Persisting History Calc ...

    VB编程资源大全(英文源码 其它)

    &lt;END&gt;&lt;br&gt;28 , calc.zip This is a basic calculator written in Visual Basic.&lt;END&gt;&lt;br&gt;29 , stopwatch.zip This shows how to count off time in a Stop Watch format.&lt;END&gt;&lt;br&gt;31 , taskhide.zip This ...

    获取硬件信息的ActiveX库

    &lt;textarea name="mbox" cols="80" rows="10"&gt; &lt;/center&gt;&lt;/td&gt; &lt;td width="9%" height="30"&gt;&lt;center&gt; ()" NAME="Button1"&gt; &lt;INPUT TYPE=button VALUE="GetCPU_ID" ONCLICK="GetCPU_ID()" NAME="Button2...

Global site tag (gtag.js) - Google Analytics