mysql中使用count()統計總結與思考


如果你的需要是統計總行數時,為什么要使用count(*),而避免使用指定具體的列名?

count()函數里面的參數是列名的的時候,那么會計算這個字段有值項的次數。也就是,該字段沒有值的項並不會進入計算范圍(就是網上常說的值為null的項不納入統計)

很多地方都有類似表述:

COUNT ( column ) counts all non-NULL occurences (or should  …  計算所有column字段為"非null"值的總數。

COUNT ( * ) counts all rows.


這樣的話,你想統計的行數並不准確。更重要的是,還會增加消耗。因為,需要判斷掃描所有行才知道值是否有值。

一般是建議以count(字段名)替代count(*)。實際使用中,我的理解是,你要統計那個列的總數,比如我想統計會員的總數,那么我可以以uid作為參考,uid是null的都不去掃描了

於是查詢就是select count(uid) from members



如果使用count(*),它會計算總行數。不管你字段是否有值都會列入計算范圍。

另外一點:myisam引擎很容易獲得總行數的統計。查詢速度變得更快。因為myisam存儲引擎已經存儲了表的總行數。

應該是每次新增加一行,這個計數器就加1。英文資料是這樣子說的:

 On MyISAM, doing a query that does SELECT COUNT(*) FROM {some_table}, is very fast, since MyISAM keeps the information in the index

也就是說,把表的總數緩存在索引中了。

 

注意一點:myisam存儲引擎的表,count(*)速度快的也僅僅是不帶where條件的count。這個想想容易理解的,因為你帶了where限制條件,原來所以中緩存的表總數能夠直接返回用嗎?不能用。這個查詢引擎也是需要根據where條件去表中掃描數據,進行統計返回的。



歸納:實際編程中統計總行數是經常用到的。此時使用count(*)多處可見。我很少看到有人使用列名作為參數:count(a)的情況。即使是這樣使用,可能其初衷也是想統計行數。只是不知道這樣所造成的細微差異而錯誤使用了"列名"的形式。

 

針對Innodb表,盡量不執行 SELECT COUNT(*) 語句,因為Innodb表沒有類似MyISAM那樣的內部計數器來記錄表記錄總量,執行這個操作將會全表掃描,速度很慢。所以呢,表的行數越多,掃描的時間就越多。當你表行數還是小數量的時候體會不出速度差距。比如百萬也感覺不出明顯。上千萬就會很明顯速度差別了。

對策:對innob存儲引擎的大表進行select count()統計總數操作,業界都會盡量避免。

如果要查詢innodb存儲引擎的表總數,要怎么辦?

總結兩種方案:

方案一:通過查詢information_schema庫,它記錄了innodb類型每個表大致的數據行數

 

方案二(更優):涉及到總數操作,專門維護一個總數。新注冊一個會員,總數值加1,需要總數的時候直接拿這個總數,比如分頁時。

方案二的擴展性更好,隨着會員表數量增大,水平切分會員表,要獲取用戶總數。可以專門看這張表。

 

在網上看到有人問自己的innodb存儲引擎的表數據行數到10億了,要進行分頁,count(*)操作很慢怎么解決。

其實像對大數據量進行統計總數的操作,並不是要求非常精准的總數,沒好多人關心差幾個。像網易,鳳凰網這些新聞有很多人評論,這個評論總數,如果每次點擊分頁的時候都進行一次count操作,那速度肯定不會快到哪里去。他們一般也是采用計數器的辦法。每次新增加一條評論,就把值加1。這樣分頁的時候直接拿這個總數進行分頁。

總數可能是存在內存中,這樣分頁計算的時候速度很快。累加操作的時候將內存中的值加1。總數這個值要持久化,還是要存到磁盤上的,也就是數據庫中(可以是關系型數據庫,也可以是mongdb這樣的數據庫很適合存儲計數)。把總數放在內存中,只是避免頻繁的磁盤i/0操作(操作數據庫就要涉及到磁盤讀寫)。

 

ps:這種計數器的思想在計算機的很多地方都會用到。比如mysql數據庫他自己的information_schema庫維護每個表的row總數,就是這樣的方式。

 

我有個疑問:針對innodb存儲引擎,使用count(1)替代count(*)就避免全表掃描,速度很快嗎?

orcalce數據庫有專門對count(1)和count(*)的區別。

count(1)其實這個1,並不是表示第一個字段,而是表示一個固定值。

count(1),其實就是計算一共有多少符合條件的行。
1並不是表示第一個字段,而是表示一個固定值。
其實就可以想成表中有這么一個字段,這個字段就是固定值1,count(1),就是計算一共有多少個1.
同理,count(2),也可以,得到的值完全一樣,count('x'),count('y')都是可以的。一樣的理解方式。在你這個語句理都可以使用,返回的值完全是一樣的。就是計數。
count(*),執行時會把星號翻譯成字段的具體名字,效果也是一樣的,不過多了一個翻譯的動作,比固定值的方式效率稍微低一些

count(1)就是不指定具體字段,固定值。

網上找不到源碼分析出count(1)到底做了什么。如果參考oracle數據庫的解釋,其實也不見得就能避免全表掃描


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM