Mysql中分頁(yè)查詢的兩個(gè)解決方法比較_PHP教程
推薦:PHP靜態(tài)調(diào)用非靜態(tài)方法的應(yīng)用分析本篇文章介紹了,PHP靜態(tài)調(diào)用非靜態(tài)方法的應(yīng)用分析。需要的朋友參考下
mysql中分頁(yè)查詢有兩種方式, 一種是使用COUNT(*)的方式,具體代碼如下
SELECT COUNT(*) FROM foo WHERE b = 1;
SELECT a FROM foo WHERE b = 1 LIMIT 100,10;
另外一種是使用SQL_CALC_FOUND_ROWS
SELECT SQL_CALC_FOUND_ROWS a FROM foo WHERE b = 1 LIMIT 100, 10;
SELECT FOUND_ROWS();
第二種方式調(diào)用SQL_CALC_FOUND_ROWS之后會(huì)將WHERE語(yǔ)句查詢的行數(shù)放在FOUND_ROWS()之中,第二次只需要查詢FOUND_ROWS()就可以查出有多少行了。
討論這兩種方法的優(yōu)缺點(diǎn):
首先原子性講,第二種肯定比第一種好。第二種能保證查詢語(yǔ)句的原子性,第一種當(dāng)兩個(gè)請(qǐng)求之間有額外的操作修改了表的時(shí)候,結(jié)果就自然是不準(zhǔn)確的了。而第二種則不會(huì)。但是非�?上�,一般頁(yè)面需要進(jìn)行分頁(yè)顯示的時(shí)候,往往并不要求分頁(yè)的結(jié)果非常準(zhǔn)確。即分頁(yè)返回的total總數(shù)大1或者小1都是無(wú)所謂的。所以其實(shí)原子性不是我們分頁(yè)關(guān)注的重點(diǎn)。
下面看效率。這個(gè)非常重要,分頁(yè)操作在每個(gè)網(wǎng)站上的使用都是非常大的,查詢量自然也很大。由于無(wú)論哪種,分頁(yè)操作必然會(huì)有兩次sql查詢,于是就有很多很多關(guān)于兩種查詢性能的比較:
SQL_CALC_FOUND_ROWS真的很慢么?
http://hi.baidu.com/thinkinginlamp/item/b122fdaea5ba23f614329b14
To SQL_CALC_FOUND_ROWS or not to SQL_CALC_FOUND_ROWS?
http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
老王這篇文章里面有提到一個(gè)covering index的概念,簡(jiǎn)單來(lái)說(shuō)就是怎樣才能只讓查詢根據(jù)索引返回結(jié)果,而不進(jìn)行表查詢
具體看他的另外一篇文章:
MySQL之Covering Index
http://hi.baidu.com/thinkinginlamp/item/1b9aaf09014acce0f45ba6d3
實(shí)驗(yàn)
結(jié)合這幾篇文章,做的實(shí)驗(yàn):
表:
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;
注意下這里是使用b,a做了一個(gè)索引,所以查詢select * 的時(shí)候是不會(huì)用到covering index的,select a才會(huì)使用到covering index
<?php
$host = '192.168.100.166';
$dbName = 'test';
$user = 'root';
$password = '';
$db = mysql_connect($host, $user, $password) or die('DB connect failed');
mysql_select_db($dbName, $db);
echo '==========================================' . "\r\n";
$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 . "\r\n";
echo '==========================================' . "\r\n";
$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 . "\r\n";
echo '==========================================' . "\r\n";
$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 * FROM foo WHERE b = 1 LIMIT 100,10");
}
$end = microtime(true);
echo $end - $start . "\r\n";
echo '==========================================' . "\r\n";
$start = microtime(true);
for ($i =0; $i<1000; $i++) {
mysql_query("SELECT SQL_NO_CACHE SQL_CALC_FOUND_ROWS * FROM foo WHERE b = 1 LIMIT 100, 10");
mysql_query("SELECT FOUND_ROWS()");
}
$end = microtime(true);
echo $end - $start . "\r\n";
返回的結(jié)果:

和老王里面文章說(shuō)的是一樣的。第四次查詢SQL_CALC_FOUND_ROWS由于不僅是沒(méi)有使用到covering index,也需要進(jìn)行全表查詢,而第三次查詢COUNT(*),且select * 有使用到index,并沒(méi)進(jìn)行全表查詢,所以有這么大的差別。
總結(jié)
PS: 另外提醒下,這里是使用MyISAM會(huì)出現(xiàn)三和四的查詢差別這么大,但是如果是使用InnoDB的話,就不會(huì)有這么大差別了。
所以我得出的結(jié)論是如果數(shù)據(jù)庫(kù)是InnoDB的話,我還是傾向于使用SQL_CALC_FOUND_ROWS
結(jié)論:SQL_CALC_FOUND_ROWS和COUNT(*)的性能在都使用covering index的情況下前者高,在沒(méi)使用covering index情況下后者性能高。所以使用的時(shí)候要注意這個(gè)。
分享:基于Zend的Captcha機(jī)制的應(yīng)用本篇文章介紹了,基于Zend的Captcha機(jī)制的應(yīng)用。需要的朋友參考下
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁(yè)面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問(wèn)控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語(yǔ)言構(gòu)造器介紹
- php/js獲取客戶端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國(guó)語(yǔ)言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
- 相關(guān)鏈接:
- 教程說(shuō)明:
PHP教程-Mysql中分頁(yè)查詢的兩個(gè)解決方法比較
。