萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL InnoDB COUNT(*) 效能優化:為何 Secondary Index 掃描比 Primary Key 快?

InnoDB 表上 COUNT(*) 全表掃描極慢。本文透過實測對比發現:利用 Secondary Index 掃描比 Primary Key 快 3 倍以上,深度解析 InnoDB 聚簇索引與輔助索引結構差異,給出優化建議。

測試環境與表結構

-- sbtest: PK=aid(BIGINT), Secondary Index=id(INT)
-- sbtest1: PK=aid(INT), Secondary Index=id(BIGINT)
-- 皆為 100 萬筆資料,InnoDB,latin1

三種 COUNT(*) 查詢效能對比

查詢方式sbtest (PK=BIGINT)sbtest1 (PK=INT)說明
COUNT(*) 無條件1.42 秒1.42 秒優化器選 PK 掃描
COUNT(*) WHERE pk >= 01.39 秒1.42 秒Range 掃描 PK,仍為全掃描
COUNT(*) WHERE secondary_idx >= 00.43 秒0.45 秒掃描 Secondary Index,快 3 倍+

關鍵發現:欄位長度互換後,Secondary Index 仍較快,證明非長度因素,而是索引結構差異。

核心原理:Clustered Index vs Secondary Index

  • Clustered Index(聚簇索引):InnoDB 將 Primary Key + 完整行資料 存在同一 B+ 樹葉節點。掃描 PK 即掃描完整行資料,I/O 量大。
  • Secondary Index(輔助索引):僅儲存 索引欄位值 + Primary Key 值,葉節點不含完整行。體積小得多,掃描速度快。

因此 COUNT(*) 只需統計行數,掃描體積最小的 Secondary Index 最划算。

為何優化器預設選 Primary Key?

InnoDB 設計者 Heikki Tuuri 解釋:

範例表中 Secondary Index 剛好是完美順序插入(極罕見)。實際上 Secondary Index 通常碎片化嚴重,導致隨機 I/O,反而比 PK 掃描慢。優化器目前無「聚類比」統計資訊,無法判斷 Secondary Index 是否接近有序。

功能請求:維護 Secondary Index 的「聚類比」統計,若接近有序則優先選擇。但該功能至今未實作。

實務優化建議

  1. 加上無意義條件強制走 Secondary Index:
    SELECT COUNT(*) FROM sbtest WHERE id >= 0;  -- id 有索引
        
  2. 維護近似計數表:觸發器/定時任務更新 table_stats(row_count),查詢直接讀取
  3. 使用 EXPLAIN 驗證執行計畫:確認 key 欄位為預期索引,Extra 顯示 Using index
  4. 大表避免頻繁 COUNT(*):改用資訊表 TABLE_ROWS(近似值)或應用層快取

延伸:MyISAM 秒級 COUNT(*)

MyISAM 維護精確行數計數器,COUNT(*) 無 WHERE 時直接回傳元資料,極快。但不支援事務、行鎖,適用場景受限。

copyright © 萬盛學電腦網 all rights reserved