MySQL的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/
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。
(二)比如说在文章系统里分页显示的时候,一般的查询是这样的:
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的更多相关文章
- mysql的SQL_CALC_FOUND_ROWS 使用
mysql的SQL_CALC_FOUND_ROWS 使用 标签: sqlmysqltable 2007-02-27 11:40 5073人阅读 评论(0) 收藏 举报 分类: Mysql数据库技术( ...
- MySQL中SQL_CALC_FOUND_ROWS的用法
1. SQL_CALC_FOUND_ROWS简述 在很多分页的程序中都这样写: #查出符合条件的记录总数 SELECT COUNT(*) from [table] WHERE ......; #查询当 ...
- mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高
mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ... ...
- 黄聪:mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高
mysql的SQL_CALC_FOUND_ROWS 使用 类似count(*) 使用性能更高 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ... ...
- MYSQL的SQL_CALC_FOUND_ROWS 和count(*)
mysql的SQL_CALC_FOUND_ROWS 和 count(*) 在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ......; 查出符合 ...
- MySQL的SQL_CALC_FOUND_ROWS真的很慢么?
分页程序一般由两条SQL组成: SELECT COUNT(*) FROM ... WHERE .... SELECT ... FROM ... WHERE LIMIT ... 如果使用SQL_CALC ...
- mysql 中 SQL_CALC_FOUND_ROWS 功能
mysql 数据库不符合sql标准的地方不少,比如TIMESTAMP列的处理,字符串比较默认大小写不敏感什么的.有时候这些问题会让你很郁闷,尤其是对从其它数据库转过来的人来说.但有些功能倒也蛮有趣. ...
- mysql的SQL_CALC_FOUND_ROWS /FOUND_ROWS()
在很多分页的程序中都这样写: SELECT COUNT(*) from `table` WHERE ......; 查出符合条件的记录总数 SELECT * FROM `table` WHERE . ...
- mysql SQL_CALC_FOUND_ROWS
mysql> ,; +----+ | id | +----+ | | | | | | | | | | +----+ rows | +--------------+ ro ...
随机推荐
- Asp.net 定时写入文本记录
Asp.net 定时写入文本记录 public static string FileAddress = "c:\\TimerLog.txt"; protected void Pag ...
- ###STL学习--迭代器
点击查看Evernote原文. #@author: gr #@date: 2014-08-23 #@email: forgerui@gmail.com STL中的迭代器. ###stl学习 |--迭代 ...
- 让C# Excel导入导出,支持不同版本的Office
问题:最近在项目中遇到,不同客户机安装不同Office版本,在导出Excel时,发生错误. 找不到Excel Com组件,错误信息如下. 未能加载文件或程序集“Microsoft.Office.Int ...
- 初尝Windows 下批处理编程
本文叫“ 初尝Windows 下批处理编程”是为了延续上一篇“初尝 Perl”,其实对于博主而言批处理以及批处理编程早就接触过了. 本文包括以下内容 1.什么是批处理 2.常用批处理命令 3.简介批处 ...
- DB2数据库中提高INSERT性能详解
分类: Linux INSERT 处理过程概述 首先让我们快速地看看插入一行时的处理步骤.这些步骤中的每一步都有优化的潜力,对此我们在后面会一一讨论. 在客户机准备 语句.对于动态 SQL,在 ...
- 使用json方式实现省市两级下拉级联菜单[原创]
本文为博主原创,转载请注明. 首先看一下实现后的效果图: 当然,要完成这个实验,mysql必须与数据库连接,这里选用navicat for mysql这款软件,它与mysql的契合度是很高的,配置环境 ...
- libipq —— iptables用户空间数据包排队库
LIBIPQ(3) NAMElibipq —— iptables用户空间数据包排队库 SYNOPSIS #include <linux/netfilter.h>#include <l ...
- Linux---文件类型及权限操作
文件类型: 用ls命令查看目录下所属文件时,每行的第一个字母标识着文件对应的文件类型 '-':代表普通文件 'd':代表目录 'c':字符设备文件 'b':块设备文件 's':套接字文件 'l':符号 ...
- C# winform关于DataGridView的一些操作
设置字段名 设置字段值 设定单元格表示 Error图标 设定当前单元格 取得当前单元格内容 取得当前单元格的列 Index 取得当前单元格的行 Index 向下一行 向上一行 取消 DataGridV ...
- HttpContext.Current多线程调用
1.在web网站的Global中,进行数据量比较大的初始化工作,而为了使用户在页面上能够及时响应,我们在Global中开启了一个线程执行该函数模块. 不过,在线程中用到HttpContext.Curr ...