MySQL做計數統計======count()=======count(*) ,count(1),count(主鍵/列名)區別=======count(1)比count(*)快對現在來說是不存在的

一:Mysql中的Count的概念:

COUNT()函數返回表中的行數。 COUNT()函數允許我們對錶中符合特定條件的所有行進行計數。

二:場景:
1:在不同的搜索引擎中,計數統計的實現方式是不一樣的;
MyISAM 引擎,比較簡單粗暴,直接將表的總行數存儲在磁盤上,因此效率很高;
InnoDB 引擎中,執行時,需要一行行的把數據查出來,然後累加;
2:場景說明:
A: count(*)包括了所有的列,相當於行數,在統計結果的時候,不會忽略列值爲NULL

並不會把全部字段取出來,而是專門做了優化,不取值,count(*)肯定不是null,按行累加

B.: count(1)包括了忽略所有列,用1代表代碼行,在統計結果的時候,不會忽略列值爲NULL

innodb引擎遍歷整張表,但不取值,返回給server層,server對於返回的每一行,放一個數字1進去,判斷是不可能爲空的,就按行累加

C: count(列名)只包括列名那一列,在統計結果的時候,會忽略列值爲空(這裏的空不是隻空字符串或者0,而是表示null)的計數,即某個字段值爲NULL時,不統計。

如果這個字段定義爲not null,一行行的從記錄裏面讀出這個字段,判斷不爲空,則累加值

如果這個字段定義允許爲null,那麼執行的時候,判斷到有可能爲null,還要把值取出來在判斷一下,不是null才累加

D: count(主鍵)

innodb引擎會遍歷整張表,把每一行的id值都取出來,返回給server層,server層判斷id值不爲空,就按行累加

三:性能說明

在 MySQL 5.7 Reference Manual 的官方手冊中:
https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count

有這麼一段:

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the
same way. There is no performance difference.

翻譯: InnoDB以相同的方式處理SELECT COUNT(*)和SELECT COUNT(1)操作。沒有性能差異。

所以按照效率排序的話,count(字段)<count(主鍵id)<count(1)≈count(*)

================着重描述一下count(*)與count(1)的區別:

COUNT(1)比COUNT()快,給出的理由是COUNT()會帶來全表掃描。而實際上兩者在高版本(5.5之後)的mysql中並沒有區別。

在MySQL5.7.23.0以後的版本,會默認對主鍵添加索引,所以結論是:

若表中有索引,COUNT()與COUNT(1)均會使用索引。由於MySQL默認對主鍵添加索引,所以對存在主鍵的表進行COUNT()、COUNT(1)查詢也都會使用主鍵索引。即兩者並沒有區別。

COUNT()有兩個非常不同的作用:它可以統計某個列值的數量,也可以統計行數。在統計列值時要求列值是非空的(不統計NULL)。如果在COUNT()的括號中定了列或者列表達式,則統計的就是這個表達式有值的結果數。…COUNT()的另一個作用是統計結果集的行數。當MySQL確認括號內的表達式值不可能爲空時,實際上就是在統計行數。最簡單的就是當我們使用COUNT()的時候,這種情況下通配符並不像我們猜想的那樣擴展成所有的列,實際上,他會忽略所有列而直接統計所有的行數“——《高性能MySQL》。

四:使用的時候的注意事項

在做計數統計的時候

count()、count(常量)和count(列名)的區別:
在《阿里巴巴Java開發手冊》中,強制建議不能使用count(1)和count(列名)來代替count(
),那這是爲什麼呢?它們之間的區別又在哪呢?
在這裏插入圖片描述

分析以及原理:

目前基於磁盤的數據庫或者搜索引擎(比如Lucene)的性能瓶頸主要都是在IO階段,相比於CPU和RAM,IO操作實在太慢了,所以這類系統的優化方向也都都是類似的——盡一切可能減少IO的次數(所以很多用ES的程序在性能優化到極限的時候選擇直接上SSD)。這裏統計行數的操作,查詢優化器的優化方向就是選擇能夠讓IO次數最少的索引,也就是基於佔用空間最小的字段所建的索引(每次IO讀取的數據量是固定的,索引佔用的空間越小所需的IO次數也就越少)。而Innodb的主鍵索引是聚簇索引(包含了KEY,除了KEY之外的其他字段值,事務ID和MVCC回滾指針)所以主鍵索引一定會比二級索引(包含KEY和對應的主鍵ID)大,也就是說在有二級索引的情況下,一般COUNT()都不會通過主鍵索引來統計行數,在有多個二級索引的情況下選擇佔用空間最小的。

如果說有張Innodb的表只有主鍵索引,而且記錄還比較大(比如30K),則統計行的操作會非常慢,因爲IO次數會很多

  • List item

所以,在對count進行優化的時候,我們可以考慮建一個比較小的二級索引; ALTER TABLE test1 ADD INDEX (status);

如果我們不要求獲取精確的總數的話,可以考慮使用explain獲取行數

關於explain

  關於explain,使用mysql的都知道,這個函數是專門用於查看sql語句的執行效率的,網上可供參考的文章很多。

定義: explain 命令速度很快,因爲 explain 用並不真正執行查詢,而是查詢優化器【估算】的行數。

  我們使用explain之後,會看到返回很多參數,其中:

rows:顯示MySQL認爲它執行查詢時必須檢查的行數。就是這個東西了,既然我們要獲取的是數據表的行數,那麼可以使用:

explain select * from table;

2、關於返回值
explain函數是會返回一個數組。這樣我們就能通過這個數組獲取到我們需求的rows。
在這裏插入圖片描述

  這裏直接獲取這個值即可。速度極快。原來查詢速度是2.33s,換成只用explain之後,速度僅爲0008s,提升十分巨大

============================= 在老版本的mysql 數據庫中
l 列名爲主鍵,count(列名)會比count(1)快

l 列名不爲主鍵,count(1)會比count(列名)快

l 如果表多個列並且沒有主鍵,則 count(1) 的執行效率優於 count(*)

l 如果有主鍵,則 select count(主鍵)的執行效率是最優的

l 如果表只有一個字段,則 select count(*)最優。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章