溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MySQL的count(*)怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2021-12-04 14:36:40 來(lái)源:億速云 閱讀:229 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要介紹“MySQL的count(*)怎么實(shí)現(xiàn)”,在日常操作中,相信很多人在MySQL的count(*)怎么實(shí)現(xiàn)問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”MySQL的count(*)怎么實(shí)現(xiàn)”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

1. 背

自從大家對(duì)于MySQL數(shù)據(jù)庫(kù)的穩(wěn)定性有了更高的追求后,經(jīng)常有小伙伴有這樣的疑問(wèn),對(duì)于count(*)這樣的操作,有沒(méi)有正確的姿勢(shì),或者有沒(méi)有可以優(yōu)化的地方?

但答案比較殘酷,如果已經(jīng)使用了正確的索引,那么基本上沒(méi)有可以優(yōu)化的地方。一旦出現(xiàn)慢查詢了,它就是慢查詢了,要改,只能自己計(jì)數(shù)或者通過(guò)其他搜索平臺(tái)來(lái)做。

今天,就一起來(lái)看看為什么會(huì)這樣,并對(duì)大家日常會(huì)遇到的一些的困惑進(jìn)行解答。

2. count(*)的實(shí)現(xiàn)方式

據(jù)說(shuō),MyISAM 引擎把一個(gè)表的總行數(shù)存在了磁盤(pán)上,因此執(zhí)行 count(*) 的時(shí)候會(huì)直接返回這個(gè)數(shù),效率很高。
而我們的mysql一般都是用Innodb的引擎,Innodb是怎么實(shí)現(xiàn)count操作的呢?
InnoDB 引擎就比較麻煩了,它執(zhí)行 count(*) 的時(shí)候,需要把數(shù)據(jù)一行一行地從引擎里面讀出來(lái),然后累積計(jì)數(shù)。
所以,當(dāng)我們的表里面的記錄越來(lái)越多的時(shí)候,count(*)就會(huì)越來(lái)越慢。

當(dāng)然,我們這里說(shuō)的都是不帶where條件的,如果帶上where條件的話,MyISAM也是很慢的。

3.正確的打開(kāi)方式

嗯,首先還是說(shuō),mysql上不太推薦用count(*)來(lái)做統(tǒng)計(jì)相關(guān)業(yè)務(wù),尤其是表非常大的情況下。
那如果業(yè)務(wù)比較小,需要快速上馬,那么,至少應(yīng)該保證count(*)帶上了科學(xué)的where條件,然后,這個(gè)表也已經(jīng)建立了科學(xué)的索引。
1)如果count(*)帶上的where條件,而且能夠走覆蓋索引,那還是可以偶爾走一走的。
2)如果count(*)帶上的where條件,能夠走索引,但是需要回表,那么這種就會(huì)比較危險(xiǎn),尤其是隨著表規(guī)模的擴(kuò)大,終究是一顆雷。
3)如果純粹count(*),或者where條件沒(méi)有任何索引,萬(wàn)萬(wàn)萬(wàn)不推薦!
那對(duì)于統(tǒng)計(jì)類的業(yè)務(wù),推薦的幾種做法:
1)帶自增id的,可以用最大id來(lái)近似獲取
2)自己計(jì)數(shù)

3)其他數(shù)據(jù)分析平臺(tái)進(jìn)行聚合

4. 能否用表統(tǒng)計(jì)信息代替count(*)

有同學(xué)在日常使用過(guò)程中,問(wèn)能否使用 系統(tǒng)表的統(tǒng)計(jì)信息 來(lái)代替count。

答案是不行。這里的tableRows只是一個(gè)參考值。

這里的表統(tǒng)計(jì)信息,實(shí)際上是使用show table status獲取的。  這個(gè)值是如何得到的呢?  我們需要了解下mysql的采樣統(tǒng)計(jì)方法。
為什么要采樣統(tǒng)計(jì)呢?  因?yàn)榘颜麖埍砣〕鰜?lái)一行行統(tǒng)計(jì),雖然可以得到精確的結(jié)果,但是代價(jià)太高了,所以只能選擇“采樣統(tǒng)計(jì)”  (所以其實(shí)mysql自己也沒(méi)有count(*)的好方法)。
采樣統(tǒng)計(jì)的時(shí)候,InnoDB 默認(rèn)會(huì)選擇 N 個(gè)數(shù)據(jù)頁(yè),統(tǒng)計(jì)這些頁(yè)面上的不同值,得到一個(gè)平均值,然后乘以這個(gè)索引的頁(yè)面數(shù),就得到了這個(gè)索引的基數(shù)。
而數(shù)據(jù)表是會(huì)持續(xù)更新的,索引統(tǒng)計(jì)信息也不會(huì)固定不變。  所以,當(dāng)變更的數(shù)據(jù)行數(shù)超過(guò) 1/M 的時(shí)候,會(huì)自動(dòng)觸發(fā)重新做一次索引統(tǒng)計(jì)。

因此,這個(gè)采樣估算得來(lái)的值,是很不準(zhǔn)的。有多不準(zhǔn)呢,官方文檔說(shuō)誤差可能達(dá)到 40% 到 50%。

4.關(guān)于那些奇奇怪怪的count(?)

在看一些老代碼查詢的時(shí)候,我們經(jīng)常會(huì)看到count(1),count(id),count(字段)等方式,那它們糾結(jié)孰優(yōu)孰劣,到底有沒(méi)有性能上的差異呢?

這里,我們先要弄清楚 count() 的語(yǔ)義。
count() 是一個(gè)聚合函數(shù),對(duì)于返回的結(jié)果集,一行行地判斷,如果 count 函數(shù)的參數(shù)不是 NULL,累計(jì)值就加 1,否則不加。  最后返回累計(jì)值。
1)count(主鍵id)
InnoDB 引擎會(huì)遍歷整張表,把每一行的 id 值都取出來(lái),返回給 server 層。  server 層拿到 id 后,判斷是不可能為空的,就按行累加。
2)count(1)
InnoDB 引擎遍歷整張表,但不取值。  server 層對(duì)于返回的每一行,放一個(gè)數(shù)字“1”進(jìn)去,判斷是不可能為空的,按行累加。
3) count(字段)
如果這個(gè)“字段”是定義為 not null 的話,一行行地從記錄里面讀出這個(gè)字段,判斷不能為 null,按行累加;
如果這個(gè)“字段”定義允許為 null,那么執(zhí)行的時(shí)候,判斷到有可能是 null,還要把值取出來(lái)再判斷一下,不是 null 才累加。
4)count(*)
并不會(huì)把全部字段取出來(lái),而是專門(mén)做了優(yōu)化,不取值。  count(*) 肯定不是 null,按行累加。
所以結(jié)論是:  按照效率排序的話,count(字段)<count(主鍵 id)<count(1)≈count(*),所以我建議,盡量使用 count(*)。

到此,關(guān)于“MySQL的count(*)怎么實(shí)現(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI