關於 COUNT(*)、COUNT(1)、COUNT(欄位) 效能差異的討論由來已久。本文釐清迷思,給出實測依據的最佳選擇指南。
| 寫法 | 統計範圍 | 效能排序 | 適用場景 |
|---|---|---|---|
| COUNT(*) | 所有列,含 NULL 列 | 有主鍵時最快 | 通用、有主鍵表 |
| COUNT(1) | 常數 1,等同 COUNT(*) | 無主鍵時較快 | 無主鍵表、Exists 子查詢 |
| COUNT(欄位) | 該欄位非 NULL 值 | 最慢(需判斷 NULL) | 需排除 NULL 統計 |
COUNT(主鍵) = COUNT(*) = COUNT(1),優化器自動轉為掃描主鍵索引,**最快**COUNT(1) 略快於 COUNT(*)(避免展開 * 解析),但差異微乎其微COUNT(*) 最快COUNT(*)/COUNT(1) 統計所有列;COUNT(col) **不統計 NULL**SELECT 1 FROM ...:回傳常數,僅判斷是否存在行(如 EXISTS 子查詢)SELECT * FROM ...:回傳所有欄位SELECT 1 避免回表,**明顯較快**SELECT COUNT(*) FROM t WHERE cond; -- 等同 SELECT SUM(1) FROM t WHERE cond; -- 同樣結果 -- SUM 可傳任意數值 SELECT SUM(5) FROM t WHERE cond; -- 回傳 5 * 滿足條件行數 SELECT SUM(-1) FROM t WHERE cond; -- 回傳 -1 * 行數
COUNT(*) 即可,語意最清晰,ANSI 標準COUNT(欄位)-- 從統計資訊取得估算值(極快,不掃表) SELECT NUM_ROWS FROM USER_TABLES WHERE TABLE_NAME = 'BIG_TABLE'; -- 或查詢區塊層級估算 SELECT BLOCKS * AVG_ROW_LEN FROM USER_TABLES WHERE TABLE_NAME = 'BIG_TABLE';