首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL COUNT(*) vs COUNT(1) vs COUNT(col) 性能實測與選型指南 (InnoDB 存儲引擎)

     編輯:MySQL 資料庫相關知識

測試環境

  • OS: Linux
  • DB: MySQL 5.5.18
  • Table: InnoDB 存儲引擎
  • 表結構:主鍵 id (INT)、二級索引 group_id (INT)、普通列 user_id (INT)、可空列 col_null (INT NULL)

實測結果與執行計劃分析

SQL使用索引掃描行數耗時結果
SELECT COUNT(*) FROM group_message二級索引 group_id (最短)852,226~0.3s852226
SELECT COUNT(1) FROM group_message二級索引 group_id (最短)852,226~0.3s852226
SELECT COUNT(group_id) FROM group_message二級索引 group_id852,226~0.3s852226
SELECT COUNT(user_id) FROM group_message組合索引 (含 user_id)852,226~0.4s852226
SELECT COUNT(col_null) FROM group_message**全表掃描 (聚簇索引)**852,226~1.2s1 (僅 1 非空)

核心結論

  1. COUNT(*) = COUNT(1) = COUNT(非空索引列):優化器識別為「統計行數」,自動選擇**最短的二級索引**掃描 (InnoDB 主鍵即數據,掃描主鍵即掃描全行,開銷最大)。性能**完全一致**。
  2. COUNT(可空列) 最慢:因可空列不在索引中 (或索引不包含 NULL),無法走索引掃描,退化為**聚簇索引全表掃描** (讀取完整行數據),I/O 開銷最大。**且不統計 NULL 值**,結果與業務「總行數」不符。
  3. 主鍵索引最「重」**:InnoDB 聚簇索引葉子節點包含完整行數據,掃描主鍵等同掃描全表。二級索引葉子節點僅含索引列+主鍵,體積小得多。
  4. 優化器智慧**:COUNT(user_id) 走組合索引而非全表掃描,證明優化器能識別「統計非空列行數」可利用包含該列的最小索引。

生產選型建議


-- ✅ 統計表總行數:首選 COUNT(*),語義清晰、標準兼容、性能最優
SELECT COUNT(*) FROM `table_name`;

-- ✅ 統計某非空列非空行數:COUNT(col) 走該列索引
SELECT COUNT(`not_null_col`) FROM `table_name`;

-- ❌ 統計可空列非空行數:全表掃描,慎用大表
SELECT COUNT(`nullable_col`) FROM `table_name`;
-- 大表建議:維護計數表 / Redis 計數器 / 觸發器異步更新

避坑指南

  • 不要信「COUNT(1) 比 COUNT(*) 快」的傳言:MySQL 內部將 COUNT(*) 優化為「不檢查列值,直接計數」,與 COUNT(1) 完全等價。
  • 大表統計行數方案**:
    1. 信息庫估算:SELECT TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA='db' AND TABLE_NAME='t'; (誤差大,僅參考)。
    2. 計數表:單獨表存計數,觸發器/應用層維護,讀取 O(1)。
    3. Redis 緩存:定時任務 SELECT COUNT(*) 回寫 Redis,業務讀 Redis。
    4. 近似值:SHOW TABLE STATUS LIKE 't'; 的 Rows 欄位。
  • 事務隔離級別影響**:RR 級別下 COUNT(*) 可能因 MVCC 看到不同快照行數,但通常可接受。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved