count(*) 對 innodb 而言,它需要把數據從磁盤中讀取出來然后累計計數;而 MyISAM 引擎把一個表的總行數存在了磁盤上,所以執行 count(*) 會直接返回這個數,如果有 where 條件則和 innodb一樣。那么如何優化 count(*) ?一個思路是使用緩存,但是需要注意雙寫一致的問題(雙寫一致性后文緩存章節會做介紹)。還可以專門設計一張表用以存儲 count(*)。
對於 count(主鍵 id )來說,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 后,判斷是不可能為空的,就按行累加。對於 count(1) 來說,InnoDB 引擎遍歷整張表,但不取值。server 層對於返回的每一行,放一個數字“1” 進去,判斷是不可能為空的,按行累加。單看這兩個用法的差別的話,你能對比出來,count(1) 執行得要比 count(主鍵 id)快。因為從引擎 返回 id 會涉及到解析數據行,以及拷貝字段值的操作。對於 count(字段)來說:如果這個“字段”是定義為 not null 的話,一行行地從記錄里面讀出這個字段,判斷不能為 null,按行累加;如果這個“字段”定義允許為 null,那么執行的時候,判斷到有可能是 null,還要把值取出來再 判斷一下,不是 null 才累加。而對於 count(*) 來說,並不會把全部字段取出來,而是專門做了優化,不取值,按行累加。所以排序效率:
count(*)=count(1)>count(id)>count(字段)