《Mysql - Count(*) 的優化》


一:Count(*) 的實現方式?

  - 要明確的是,在不同的 MySQL 引擎中count(*) 有不同的實現方式。

  - MyISAM 引擎把一個表的總行數存在了磁盤上,因此執行 count(*) 的時候會直接返回這個數,效率很高(前提是不加where條件)

  - 而 InnoDB 引擎就麻煩了,它執行 count(*) 的時候,需要把數據一行一行地從引擎里面讀出來,然后累積計數。

 

二: 為什么 InnoDB 不跟 MyISAM 一樣,也把數字存起來呢?

  -  因為即使是在同一個時刻的多個查詢,由於多版本並發控制(MVCC)的原因,InnoDB 表“應該返回多少行”也是不確定的

  - 也是和MVCC獲取一致性視圖的問題。具體要抓取哪個一致性視圖作為標准。

  - 每一行記錄都要判斷自己是否對這個會話可見,因此對於 count(*) 請求來說,InnoDB 只好把數據一行一行地讀出依次判斷,可見的行才能夠用於計算“基於這個查詢”的表的總行數。

 

三:MyIsam 和 InnoDB 的總結。

  - MyISAM 表雖然 count(*) 很快,但是不支持事務;

  - show table status 命令雖然返回很快,但是不准確;(空洞問題)

  - InnoDB 表直接 count(*) 會遍歷全表,雖然結果准確,但會導致性能問題。 

 

四: Count ?

  - 概念

    - count() 是一個聚合函數,對於返回的結果集,一行行地判斷,如果 count 函數的參數不是 NULL,累計值就加 1,否則不加。最后返回累計值

 

  - 區分(不同的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(*) 肯定不是 null,按行累加。

 

    - 所以結論是:按照效率排序的話,count(字段)<count(主鍵 id)<count(1)≈count(*),建議盡量使用 count(*)。

 

五:解決 count 性能問題

  - 緩存記錄條數 (注意緩存和數據庫的一致性問題)

  - 數據庫記錄條數(類型匯總表,開啟事務,保證一致性問題)

  - 使用 explain / show table status 等近似值(不准確)


免責聲明!

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



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