| 場景 | COUNT(*) | COUNT(col) | 說明 |
|---|---|---|---|
| 無 WHERE 條件 | 極快(MyISAM 直接讀表元資料;InnoDB 掃描最小索引) | 較慢(需掃描指定列,檢查 NULL) | MyISAM 有行數快取,InnoDB 無 |
| 有 WHERE 條件 | 掃描索引/表過濾 | 掃描索引/表過濾 + 額外判斷 col IS NOT NULL | COUNT(*) 顯著快於 COUNT(col) |
mysql> SELECT COUNT(*) FROM cdb_posts WHERE fid = 604;
+----------+
| COUNT(*) |
+----------+
| 79000 |
+----------+
1 row in set (0.03 sec)
mysql> SELECT COUNT(tid) FROM cdb_posts WHERE fid = 604;
+------------+
| COUNT(tid) |
+------------+
| 79000 |
+------------+
1 row in set (0.33 sec) -- 慢 10 倍!
mysql> SELECT COUNT(pid) FROM cdb_posts WHERE fid = 604;
+------------+
| COUNT(pid) |
+------------+
| 79000 |
+------------+
1 row in set (0.33 sec)
COUNT(*) 統計「符合條件的行數」;COUNT(col) 統計「col 非 NULL 的行數」。後者需額外讀取列值並判斷 NULL。COUNT(*) 通常掃描最小的二級索引(或主鍵);COUNT(col) 若 col 無索引或非覆蓋索引,可能觸發回表或全表掃描。COUNT(*) 有專門優化路徑(選擇最小索引掃描),而 COUNT(col) 不享受此優化。WHERE 時:COUNT(*) 直接讀取表元資料 table_rows,**O(1)** 完成。WHERE 時:必須全表掃描,無捷徑。SELECT COUNT(*) FROM table。SELECT COUNT(*) FROM table WHERE col = 'val':若頻繁查詢,建議建立覆蓋索引 INDEX idx_col (col) 或 INDEX idx_col_other (col, other_col) 使掃描只走索引。SELECT COUNT(col) FROM table WHERE col2 = 'val':雙重打擊(掃描 + 判 NULL),改寫為 COUNT(*) + 覆蓋索引。WHERE 1 vs WHERE 1=1WHERE 1 AND col='value' -- 極快,優化器直接忽略常數條件
WHERE 1=1 AND col='value' -- 較慢,某些版本優化器未完全消除常數表達式
建議程式碼動態拼接 SQL 時統一用 WHERE 1 作為基礎條件。
EXPLAIN SELECT COUNT(*) ... 觀察 rows 估算值(InnoDB 統計資訊,誤差 ±10%)。summary_table 定時 INSERT ... ON DUPLICATE KEY UPDATE cnt=cnt+1 累加。INCR key,讀取 GET key,定期同步落庫。