MySQL?count(*)統(tǒng)計(jì)總數(shù)問(wèn)題匯總
在日常開(kāi)發(fā)工作中,我經(jīng)常會(huì)遇到需要統(tǒng)計(jì)總數(shù)的場(chǎng)景,比如:統(tǒng)計(jì)訂單總數(shù)、統(tǒng)計(jì)用戶(hù)總數(shù)等。一般我們會(huì)使用MySQL 的count函數(shù)進(jìn)行統(tǒng)計(jì),但是隨著數(shù)據(jù)量逐漸增大,統(tǒng)計(jì)耗時(shí)也越來(lái)越長(zhǎng),最后竟然出現(xiàn)慢查詢(xún)的情況,這究竟是什么原因呢?本篇文章帶你一下學(xué)習(xí)一下。
1. MyISAM存儲(chǔ)引擎計(jì)數(shù)為什么這么快?
我們總有個(gè)錯(cuò)覺(jué),就是感覺(jué)MyISAM引擎的count計(jì)數(shù)要比InnoDB引擎更快,實(shí)際這不是錯(cuò)覺(jué)。
MyISAM引擎把表的總行數(shù)單獨(dú)記錄在磁盤(pán)上,查詢(xún)的時(shí)候可以直接返回,不需要再累加統(tǒng)計(jì)。
但是當(dāng)SQL查詢(xún)中有where條件的時(shí)候,就無(wú)法再使用表的總行數(shù)了,還是需要乖乖的進(jìn)行累加統(tǒng)計(jì),查詢(xún)性能也就跟InnoDB相差無(wú)幾了。
為什么MyISAM引擎能夠記錄表的總行數(shù),InnoDB引擎卻不行?
因?yàn)镸yISAM引擎不支持事務(wù),只有表鎖,所以記錄的總行數(shù)是準(zhǔn)確的。
而InnoDB引擎支持事務(wù)和行鎖,存在并發(fā)修改的情況。又由于事務(wù)的隔離性,會(huì)出現(xiàn)不可重復(fù)讀和幻讀,記錄的總行數(shù)無(wú)法保證是準(zhǔn)確的。
2. 能不能手動(dòng)實(shí)現(xiàn)統(tǒng)計(jì)總行數(shù)
既然InnoDB引擎沒(méi)有幫我們記錄總行數(shù),我們能不能手動(dòng)記錄總行數(shù),比如使用Redis。
其實(shí)也是不行的,使用Redis記錄總行數(shù),至少有下面3個(gè)問(wèn)題:
- 無(wú)法實(shí)現(xiàn)事務(wù)之間的隔離
- 更新丟失,因?yàn)閕++不是原子操作,當(dāng)然可以使用Lua腳本實(shí)現(xiàn)原子操作,更復(fù)雜。
- Redis是非關(guān)系型緩存數(shù)據(jù)庫(kù),不能當(dāng)作關(guān)系型持久化數(shù)據(jù)庫(kù)使用,一般需要設(shè)置過(guò)期時(shí)間。
由上圖中得知,雖然Redis計(jì)數(shù)加1操作放在了事務(wù)里面,但是不受事務(wù)控制的,在事務(wù)沒(méi)有提交前,其他查詢(xún)依然讀到了最新的總行數(shù),這就是臟讀的情況。
3. InnoDB引擎能否實(shí)現(xiàn)快速計(jì)數(shù)
有一種辦法,可以粗略估計(jì)表的總行數(shù),就是使用MySQL命令:
show table status like 'user';
真實(shí)的總行數(shù)有100萬(wàn)行,預(yù)估有99萬(wàn)多行,誤差在可接受的范圍內(nèi)。
部分場(chǎng)景適用,比如粗略估計(jì)網(wǎng)站的總用戶(hù)數(shù)。
4. 四種計(jì)數(shù)方式的性能差別
常見(jiàn)的統(tǒng)計(jì)總行數(shù)的方式有以下四種:
count(*) 、 count(常量) 、 count(id) 、 count(字段)
InnoDB引擎對(duì)count計(jì)數(shù)做了優(yōu)化,會(huì)選用數(shù)據(jù)量較小的非聚簇索引進(jìn)行統(tǒng)計(jì)。
比如用戶(hù)表中有三個(gè)索引,分別是主鍵索引、name索引和age索引,使用執(zhí)行計(jì)劃查看計(jì)數(shù)的時(shí)候用到了哪個(gè)索引?
CREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主鍵', `name` varchar(100) DEFAULT NULL COMMENT '姓名', `age` tinyint NOT NULL, PRIMARY KEY (`id`), KEY `idx_name` (`name`), KEY `idx_age` (`age`) ) ENGINE=InnoDB COMMENT='用戶(hù)表';
explain select count(*) from user;
用到了數(shù)據(jù)量較小的age索引。
count(*) 、 count(常量) 是直接統(tǒng)計(jì)表中的總行數(shù),效率較高。
而 count(id) 還需要把數(shù)據(jù)返回給MySQL Server端進(jìn)行累加計(jì)數(shù)。
最后 count(字段)需要篩選不為null字段,效率最差。
四種計(jì)數(shù)的查詢(xún)性能從高到低,依次是:
count(*) ≈ count(常量) > count(id) > count(字段)
對(duì)于大多數(shù)情況,得到計(jì)數(shù)結(jié)果,還是老老實(shí)實(shí)使用count(*)
所以推薦使用select count(*),別跟**select *搞混了,不推薦使用select ***的。
到此這篇關(guān)于MySQL count(*)統(tǒng)計(jì)總數(shù)的文章就介紹到這了,更多相關(guān)MySQL count(*)統(tǒng)計(jì)總數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
開(kāi)啟bin-log日志mysql報(bào)錯(cuò)的解決方法
開(kāi)啟bin-log日志mysql報(bào)錯(cuò):This function has none of DETERMINISTIC, NO SQL解決辦法,大家參考使用吧2013-12-12Idea 如何導(dǎo)入Mysql8.0驅(qū)動(dòng)jar包
IDEA中的庫(kù)(Libraries)就是用來(lái)存放外部jar包,我們的項(xiàng)目或模塊需要某些jar包時(shí),可以從這里把包導(dǎo)入到模塊依賴(lài)(Dependencies)中,本文給大家介紹Idea 如何導(dǎo)入Mysql8.0驅(qū)動(dòng)jar包,感興趣的朋友一起看看吧2023-12-12win8.1安裝mysql5.6時(shí)遇到問(wèn)題解決方案
本文主要記錄的是作者在win8.1安裝mysql5.6時(shí)遇到問(wèn)題的解決方案,網(wǎng)上查了很多方法都沒(méi)能解決,這里把最后的方法分享給大家2016-10-10關(guān)于Mysql-connector-java驅(qū)動(dòng)版本問(wèn)題總結(jié)
這篇文章主要介紹了Mysql-connector-java驅(qū)動(dòng)版本問(wèn)題,本文給大家介紹的很詳細(xì),通過(guò)原因說(shuō)明問(wèn)題小結(jié)個(gè)人建議給大家展示的很好,需要的朋友可以參考下2021-06-06解決SQL文件導(dǎo)入MySQL數(shù)據(jù)庫(kù)1118錯(cuò)誤的問(wèn)題
在使用Navicat導(dǎo)入SQL文件時(shí),有時(shí)會(huì)遇到報(bào)錯(cuò)問(wèn)題,這通常與MySQL版本差異或嚴(yán)格模式設(shè)置有關(guān),若報(bào)錯(cuò)提示rowsize長(zhǎng)度過(guò)長(zhǎng),可能是因?yàn)镸ySQL的嚴(yán)格模式開(kāi)啟導(dǎo)致,解決方法是檢查嚴(yán)格模式是否開(kāi)啟,若開(kāi)啟則需關(guān)閉2024-10-10MySQL explain根據(jù)查詢(xún)計(jì)劃去優(yōu)化SQL語(yǔ)句
MySQL是一種常見(jiàn)的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),常被用于各種應(yīng)用程序中存儲(chǔ)數(shù)據(jù),當(dāng)涉及到大量的數(shù)據(jù)時(shí),就需要MySQL的explain功能來(lái)幫助優(yōu)化,本文將詳細(xì)介紹MySQL的explain功能,感興趣的朋友可以參考閱讀2023-04-04mysql創(chuàng)建用戶(hù)并賦予用戶(hù)權(quán)限詳細(xì)操作教程
這篇文章主要給大家介紹了關(guān)于mysql創(chuàng)建用戶(hù)并賦予用戶(hù)權(quán)限詳細(xì)操作的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12MySQL5.7限制general_log日志大小的實(shí)現(xiàn)
MySQL5.7.41中為避免通用查詢(xún)?nèi)罩緂eneral_log快速增長(zhǎng)占用硬盤(pán)空間,可以通過(guò)定時(shí)任務(wù)執(zhí)行腳本進(jìn)行每日備份或清理,從而限制其大小,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-10-10