Mysql聚合函數count(*) 的性能分析

你首先要明確的是,在不一樣的 MySQL 引擎中,count(*) 有不一樣的實現方式。函數

  • MyISAM 引擎把一個表的總行數存在了磁盤上,所以執行 count(*) 的時候會直接返回這個數,效率很高;
  • 而 InnoDB 引擎就麻煩了,它執行 count(*) 的時候,須要把數據一行一行地從引擎裏面讀出來,而後累積計數。

在 select count(?) from t 這樣的查詢語句裏面,count(*)、count(主鍵 id)、count(字段) 和 count(1) 等不一樣用法的性能,有哪些差異?性能

須要注意的是,下面的討論仍是基於 InnoDB 引擎的。優化

這裏,首先你要弄清楚 count() 的語義。count() 是一個聚合函數,對於返回的結果集,一行行地判斷,若是 count 函數的參數不是 NULL,累計值就加 1,不然不加。最後返回累計值。spa

因此,count(*)、count(主鍵 id) 和 count(1) 都表示返回知足條件的結果集的總行數;而 count(字段),則表示返回知足條件的數據行裏面,參數「字段」不爲 NULL 的總個數。server

至於分析性能差異的時候,你能夠記住這麼幾個原則:排序

  1. server 層要什麼就給什麼;效率

  2. InnoDB 只給必要的值;select

  3. 如今的優化器只優化了 count(*) 的語義爲「取行數」,其餘「顯而易見」的優化並無作。遍歷

這是什麼意思呢?接下來,咱們就一個個地來看看。數據

一、對於 count(主鍵 id) 來講,InnoDB 引擎會遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 後,判斷是不可能爲空的,就按行累加。

二、對於 count(1) 來講,InnoDB 引擎遍歷整張表,但不取值。server 層對於返回的每一行,放一個數字「1」進去,判斷是不可能爲空的,按行累加。

單看這兩個用法的差異的話,你能對比出來,count(1) 執行得要比 count(主鍵 id) 快。由於從引擎返回 id 會涉及到解析數據行,以及拷貝字段值的操做。

三、對於 count(字段) 來講:

  3.一、若是這個「字段」是定義爲 not null 的話,一行行地從記錄裏面讀出這個字段,判斷不能爲 null,按行累加;

  3.二、若是這個「字段」定義容許爲 null,那麼執行的時候,判斷到有多是 null,還要把值取出來再判斷一下,不是 null 才累加。

也就是前面的第一條原則,server 層要什麼字段,InnoDB 就返回什麼字段。

可是 count(*) 是例外,並不會把所有字段取出來,而是專門作了優化,不取值。count(*) 確定不是 null,按行累加。

因此結論是:按照效率排序的話,count(字段)<count(主鍵 id)<count(1)≈count(*),因此我建議你,儘可能使用 count(*)。

相關文章
相關標籤/搜索