1. 程式人生 > 其它 >MySQL 中 count(*) 和 count(1)

MySQL 中 count(*) 和 count(1)

一張有 100W 條資料的表

CREATETABLE`user`(
`id`int(11)unsignedNOTNULLAUTO_INCREMENT,
`username`varchar(255)DEFAULTNULL,
`address`varchar(255)DEFAULTNULL,
`password`varchar(255)DEFAULTNULL,
PRIMARYKEY(`id`)
)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

====>

explain 分析

  • type:前三個的 type 值為 index,表示全索引掃描,就是把整個索引過一遍就行(注意是索引不是整個表
    );後兩個的 type 值為 all,表示全表掃描,即不會使用索引。
  • key:這個表示 MySQL 決定採用哪個索引來優化對該表的訪問,PRIMARY 表示利用主鍵索引,NULL 表示不用索引。
  • key_len:這個表示 MySQL 使用的鍵長度,因為我們的主鍵型別是 INT 且非空,所以值為 4。
  • Extra:這個中的 Using index 表示優化器只需要通過訪問索引就可以獲取到需要的資料(不需要回表)。

原理分析:

主鍵索引和普通索引的儲存又有所不同:

在主鍵索引中,葉子結點儲存了每一行的資料。而在普通索引中,葉子結點儲存的是主鍵值,當我們使用普通索引去搜索資料的時候,先在葉子結點中找到主鍵,再拿著主鍵去主鍵索引中查詢資料,相當於做了兩次查詢,這也就是我們平常所說的回表

操作。

對於select count(1) from user;這個查詢來說,InnoDB 引擎會去找到一個最小的索引樹去遍歷(不一定是主鍵索引),但是不會讀取資料,而是讀到一個葉子節點,就返回 1,最後將結果累加。

對於select count(id) from user;這個查詢來說,InnoDB 引擎會遍歷整個主鍵索引,然後讀取 id 並返回,不過因為 id 是主鍵,就在 B+ 樹的葉子節點上,所以這個過程不會涉及到隨機 IO(並不需要回表等操作去資料頁拿資料),效能也是 OK 的。

對於select count(username) from user;

這個查詢來說,InnoDB 引擎會遍歷整張表做全表掃描,讀取每一行的 username 欄位並返回,如果 username 在定義時候設定了 not null,那麼直接統計 username 的個數;如果 username 在定義的時候沒有設定 not null,那麼就先判斷一下 username 是否為空,然後再統計。

select count(*) from user;,這個 SQL 的特殊之處在於它被 MySQL 優化過,當 MySQL 看到count(*)就知道你是想統計總記錄數,就會去找到一個最小的索引樹去遍歷,然後統計記錄數。

=========>為主鍵索引(聚集索引)的葉子節點是資料,而普通索引的葉子節點則是主鍵值,所以普通索引的索引樹要小一些。然而在上文的案例中,我們只有主鍵索引,所以最終使用的就是主鍵索引。

結論:

第一個查詢效能最高,第二個次之(因為需要讀取 id 並返回),第三個最差(因為需要全表掃描),第四個的查詢效能則接近第一個。