MySQL?count(*)統(tǒng)計總數(shù)問題匯總
在日常開發(fā)工作中,我經常會遇到需要統(tǒng)計總數(shù)的場景,比如:統(tǒng)計訂單總數(shù)、統(tǒng)計用戶總數(shù)等。一般我們會使用MySQL 的count函數(shù)進行統(tǒng)計,但是隨著數(shù)據(jù)量逐漸增大,統(tǒng)計耗時也越來越長,最后竟然出現(xiàn)慢查詢的情況,這究竟是什么原因呢?本篇文章帶你一下學習一下。
1. MyISAM存儲引擎計數(shù)為什么這么快?
我們總有個錯覺,就是感覺MyISAM引擎的count計數(shù)要比InnoDB引擎更快,實際這不是錯覺。
MyISAM引擎把表的總行數(shù)單獨記錄在磁盤上,查詢的時候可以直接返回,不需要再累加統(tǒng)計。
但是當SQL查詢中有where條件的時候,就無法再使用表的總行數(shù)了,還是需要乖乖的進行累加統(tǒng)計,查詢性能也就跟InnoDB相差無幾了。
為什么MyISAM引擎能夠記錄表的總行數(shù),InnoDB引擎卻不行?
因為MyISAM引擎不支持事務,只有表鎖,所以記錄的總行數(shù)是準確的。
而InnoDB引擎支持事務和行鎖,存在并發(fā)修改的情況。又由于事務的隔離性,會出現(xiàn)不可重復讀和幻讀,記錄的總行數(shù)無法保證是準確的。
2. 能不能手動實現(xiàn)統(tǒng)計總行數(shù)
既然InnoDB引擎沒有幫我們記錄總行數(shù),我們能不能手動記錄總行數(shù),比如使用Redis。
其實也是不行的,使用Redis記錄總行數(shù),至少有下面3個問題:
- 無法實現(xiàn)事務之間的隔離
- 更新丟失,因為i++不是原子操作,當然可以使用Lua腳本實現(xiàn)原子操作,更復雜。
- Redis是非關系型緩存數(shù)據(jù)庫,不能當作關系型持久化數(shù)據(jù)庫使用,一般需要設置過期時間。

由上圖中得知,雖然Redis計數(shù)加1操作放在了事務里面,但是不受事務控制的,在事務沒有提交前,其他查詢依然讀到了最新的總行數(shù),這就是臟讀的情況。
3. InnoDB引擎能否實現(xiàn)快速計數(shù)
有一種辦法,可以粗略估計表的總行數(shù),就是使用MySQL命令:
show table status like 'user';

真實的總行數(shù)有100萬行,預估有99萬多行,誤差在可接受的范圍內。
部分場景適用,比如粗略估計網(wǎng)站的總用戶數(shù)。
4. 四種計數(shù)方式的性能差別
常見的統(tǒng)計總行數(shù)的方式有以下四種:
count(*) 、 count(常量) 、 count(id) 、 count(字段)
InnoDB引擎對count計數(shù)做了優(yōu)化,會選用數(shù)據(jù)量較小的非聚簇索引進行統(tǒng)計。
比如用戶表中有三個索引,分別是主鍵索引、name索引和age索引,使用執(zhí)行計劃查看計數(shù)的時候用到了哪個索引?
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='用戶表';
explain select count(*) from user;

用到了數(shù)據(jù)量較小的age索引。
count(*) 、 count(常量) 是直接統(tǒng)計表中的總行數(shù),效率較高。
而 count(id) 還需要把數(shù)據(jù)返回給MySQL Server端進行累加計數(shù)。
最后 count(字段)需要篩選不為null字段,效率最差。
四種計數(shù)的查詢性能從高到低,依次是:
count(*) ≈ count(常量) > count(id) > count(字段)
對于大多數(shù)情況,得到計數(shù)結果,還是老老實實使用count(*)
所以推薦使用select count(*),別跟**select *搞混了,不推薦使用select ***的。
到此這篇關于MySQL count(*)統(tǒng)計總數(shù)的文章就介紹到這了,更多相關MySQL count(*)統(tǒng)計總數(shù)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于Mysql-connector-java驅動版本問題總結
這篇文章主要介紹了Mysql-connector-java驅動版本問題,本文給大家介紹的很詳細,通過原因說明問題小結個人建議給大家展示的很好,需要的朋友可以參考下2021-06-06
解決SQL文件導入MySQL數(shù)據(jù)庫1118錯誤的問題
在使用Navicat導入SQL文件時,有時會遇到報錯問題,這通常與MySQL版本差異或嚴格模式設置有關,若報錯提示rowsize長度過長,可能是因為MySQL的嚴格模式開啟導致,解決方法是檢查嚴格模式是否開啟,若開啟則需關閉2024-10-10
MySQL explain根據(jù)查詢計劃去優(yōu)化SQL語句
MySQL是一種常見的關系型數(shù)據(jù)庫管理系統(tǒng),常被用于各種應用程序中存儲數(shù)據(jù),當涉及到大量的數(shù)據(jù)時,就需要MySQL的explain功能來幫助優(yōu)化,本文將詳細介紹MySQL的explain功能,感興趣的朋友可以參考閱讀2023-04-04
mysql創(chuàng)建用戶并賦予用戶權限詳細操作教程
這篇文章主要給大家介紹了關于mysql創(chuàng)建用戶并賦予用戶權限詳細操作的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12
MySQL5.7限制general_log日志大小的實現(xiàn)
MySQL5.7.41中為避免通用查詢日志general_log快速增長占用硬盤空間,可以通過定時任務執(zhí)行腳本進行每日備份或清理,從而限制其大小,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-10-10

