分页程序一般由两条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/

MySQL之Covering Index

在网上随便搜搜,就能找到大把的关于MySQL优化的文章,不过里面很多都不准确,说个常见的:

SELECT a FROM ... WHERE b = ...

一般来说,很多文章会告诫你类似这样的查询,不要在“a”字段上建立索引,而应该在“b”上建立索引。这样做确实不错,但是很多时候这并不是最佳结果。为什么这样说?让我们先来分析一下查询的处理过程:在执行查询时,系统会查询“b”索引进行定位,然后再利用此定位去表里查询需要的数据“a”。也就是说,在这个过程中存在两次查询,一次是查询索引,另一次是查询表。那有没有办法用一次查询搞定问题呢?有,就是Covering Index!所谓Covering Index,就是说不必查询表文件,单靠查询索引文件即可完成。具体到此例中就是建立一个复合索引“b, a”,当查询进行时,通过复合索引的“b”部分去定位,至于需要的数据“a”,立刻就可以在索引里得到,从而省略了表查询的过程。

如果你想利用Covering Index,那么就要注意SELECT方式,只SElECT必要的字段,千万别SELECT *,因为我们不太可能把所有的字段一起做索引,虽然可以那样做,但那样会让索引文件过大,结果反倒会弄巧成拙。

如何才能确认查询使用了Covering Index呢?很简单,使用explain即可!只要在Extra里出现Using index就说明使用的是Covering Index。

知道了以上这些知识,估计对Coverging Index的了解也差不多了。再举两个例子,让大家印象深点:

(一)比如说在文章系统里统计总数的时候,一般的查询是这样的:

SELECT COUNT(*) FROM articles WHERE category_id = ...

当我们在category_id建立索引后,这个查询使用的就是Covering Index。

参考文档:COUNT(*) vs COUNT(col)

(二)比如说在文章系统里分页显示的时候,一般的查询是这样的:

SELECT id, title, content FROM article ORDER BY created DESC LIMIT 10000, 10;

通常这样的查询会把索引建在created字段(其中id是主键),不过当LIMIT偏移很大时,查询效率仍然很低,改变一下查询:

SELECT id, title, content FROM article
INNER JOIN (
    SELECT id FROM article ORDER BY created DESC LIMIT 10000, 10
) AS page USING(id)

此时,建立复合索引"created, id"就可以在子查询里利用上Covering Index,快速定位id,查询效率嗷嗷的。

Covering Index并不是什么很难的概念,但是人们往往会忽视它的价值,希望本文能给你提个醒。

更多:http://blog.itpub.net/758322/viewspace-680921/

MySQL的SQL_CALC_FOUND_ROWS的更多相关文章

  1. mysql的SQL_CALC_FOUND_ROWS 使用

    mysql的SQL_CALC_FOUND_ROWS 使用 标签: sqlmysqltable 2007-02-27 11:40 5073人阅读 评论(0) 收藏 举报  分类: Mysql数据库技术( ...

  2. MySQL中SQL_CALC_FOUND_ROWS的用法

    1. SQL_CALC_FOUND_ROWS简述 在很多分页的程序中都这样写: #查出符合条件的记录总数 SELECT COUNT(*) from [table] WHERE ......; #查询当 ...

  3. mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高

    mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ... ...

  4. 黄聪:mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高

    mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ... ...

  5. MYSQL的SQL_CALC_FOUND_ROWS 和count(*)

    mysql的SQL_CALC_FOUND_ROWS 和 count(*) 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ......;  查出符合 ...

  6. MySQL的SQL_CALC_FOUND_ROWS真的很慢么?

    分页程序一般由两条SQL组成: SELECT COUNT(*) FROM ... WHERE .... SELECT ... FROM ... WHERE LIMIT ... 如果使用SQL_CALC ...

  7. mysql 中 SQL_CALC_FOUND_ROWS 功能

    mysql 数据库不符合sql标准的地方不少,比如TIMESTAMP列的处理,字符串比较默认大小写不敏感什么的.有时候这些问题会让你很郁闷,尤其是对从其它数据库转过来的人来说.但有些功能倒也蛮有趣. ...

  8. mysql的SQL_CALC_FOUND_ROWS /FOUND_ROWS()

    在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ......;  查出符合条件的记录总数 SELECT * FROM `table` WHERE . ...

  9. mysql SQL_CALC_FOUND_ROWS

    mysql> ,; +----+ | id | +----+ |   | |   | |   | |   | |   | +----+  rows  | +--------------+  ro ...

随机推荐

  1. JQuery 之 Ajax 异步和同步浅谈

    Ajax 同步和异步的区别 同步是当 JS 代码加载到当前 Ajax 的时候会把页面里所有的代码停止加载,页面出现假死状态:当这个 Ajax 执行完毕后才会继续运行其他代码此时页面假死状态才会解除.反 ...

  2. 一种c#深拷贝方式完胜java深拷贝(实现上的对比)

    楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心.却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的情况.(实在是不想自己new ...

  3. python 安装mysql 客户端遇到的问题

    一. Win7 64位编译Python扩展解决”error: Unable to find vcvarsall.bat”问题   系统上安装有Visual Studio 2010以及相应的SDK,然后 ...

  4. Struts2文件上传方式与上传失败解决方式

    首先将几个对象弄出来第一个 上传页面第二个 上传action第三个 startut2配置文件 我的文字描述不是很好,但是终归是自己写出来的,后来我在网上看到一篇关于文件上传描述的非常清楚的文章, 链接 ...

  5. JS的词法作用域

    词法作用域定义实现的规则: 1 函数作用域实在定义的时候决定的,而不是在执行时候决定 2 为了实现这种词法作用域,函数内部不仅包含函数代码逻辑,还必须引用当前的作用域链. 3 函数对象可以通过作用域链 ...

  6. 【HeadFirst设计模式】12.复合模式

    定义: 复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题. 要点: MVC模式是复合模式,结合了观察者模式.策略模式和组合模式. 模型使用了观察者模式,以便观察者更新,同时保存 ...

  7. 布局时margin会影响父元素

    布局时margin会影响父元素.md 在布局使用margin时 <div class="login-bg"> <div class="login&quo ...

  8. mysql批量更新、多表更新、多表删除

    本文介绍下,mysql中进行批量更新.多表更新.多表删除的一些实例,有需要的朋友可以参考下. 本节主要内容: mysql的批量更新.多表更新.多表删除 一,批量更新: 复制代码代码示例: update ...

  9. Nginx禁止通过IP,未绑定域名访问服务器

    这几天查看CNZZ统计后台看到,我的IP被两个未知的域名绑定了,为了避免被天朝和谐掉, 可以在Nginx上设置禁止通过IP访问服务器,只能通过绑定域名访问(同时设置未绑定域名返回500错误或者跳转到我 ...

  10. 一次Oracle数据迁移

    目标数据库:Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 源数据库  : Oracle Database 11g Enterpri ...