首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

MSSQL 效能大比拚:COUNT(*) vs COUNT(欄位) vs 系統表查詢 — 千萬筆資料實測

     編輯:關於SqlServer

測試環境與資料規模

  • 資料表:Articles (文章表)
  • 筆數:6,069 萬筆
  • 結構:ArticleID (PK, IDENTITY, Clustered Index) + ATitle (NVARCHAR(100)) + AContent (VARCHAR(2000)) + CreateDate (DATETIME)
  • 硬體:典型伺服器規格 (文中未詳述,重點在相對比較)

測試腳本與指標

DBCC FREEPROCCACHE; -- 清除計畫快取
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

-- 測試語句置於此
GO

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

觀測指標:CPU 時間、經過時間、邏輯讀取。

實測結果對比

查詢語句CPU 時間 (ms)經過時間 (ms)邏輯讀取掃描模式
SELECT COUNT(*) FROM Articles1,1251,140120,368Clustered Index Scan
SELECT COUNT(ArticleID) FROM Articles1,0931,094120,368Clustered Index Scan
SELECT COUNT(ATitle) FROM Articles2,2662,267~240,000+Clustered Index Scan + 解壓縮 NVARCHAR
SELECT COUNT(AContent) FROM Articles2,2962,303~400,000+Clustered Index Scan + 解壓縮 VARCHAR(MAX) 離列儲存

深度解析

為什麼 COUNT(*) ≈ COUNT(PK) 最快?

  • COUNT(*) 語意為「計算列數」,優化器直接掃描最窄索引 (通常是叢集索引或最小非叢集索引) 的葉層頁面計數,不檢查 NULL。
  • COUNT(PK) 因 PK 為 NOT NULL,語意等同 COUNT(*),優化器同樣走最窄索引掃描。
  • 兩者執行計畫幾乎相同,微小差異屬測試噪音。

為什麼 COUNT(文字欄位) 慢 2 倍?

  • 語意為「計算非 NULL 值個數」,必須讀取該欄位實際值 判斷是否 NULL。
  • NVARCHAR(100) 需解壓縮 Unicode;VARCHAR(2000) 可能觸發離列儲存 (LOB) 讀取,邏輯讀取量暴增。
  • 若欄位允許 NULL 且無索引覆蓋,必須掃描叢集索引 (含所有欄位) → I/O 最大。

極速替代方案:查詢系統目錄視圖

-- 瞬間完成,無 I/O 掃描
SELECT SUM(p.rows) 
FROM sys.partitions p
WHERE p.object_id = OBJECT_ID('Articles') AND p.index_id IN (0,1); -- 0=堆疊, 1=叢集索引

結果:CPU < 1ms,邏輯讀取 ≈ 0。
原理:sys.partitions.rows 由儲存引擎維護的中繼資料,不保證 100% 即時精確 (未提交交易、延遲更新),但誤差極小,適合「近似總筆數」報表、分頁總頁數估算。

進階:搭配索引覆蓋優化 COUNT(欄位)

若頻繁 COUNT(ATitle) 且該欄位常用於查詢:

CREATE NONCLUSTERED INDEX IX_Articles_ATitle_Cover ON Articles(ATitle) INCLUDE (ArticleID);
-- 或僅建立欄位索引 (若不需覆蓋其他查詢)
CREATE NONCLUSTERED INDEX IX_Articles_ATitle ON Articles(ATitle);

此後 COUNT(ATitle) 可掃描此窄索引 而非叢集索引,I/O 大幅降低。

最佳實踐建議

  1. 只要總筆數:用 COUNT(*) (語意最清晰) 或系統表 sys.partitions (極速、近似值)。
  2. 需排除 NULL:用 COUNT(NotNullColumn),確保該欄有索引或建立覆蓋索引。
  3. 避免 COUNT(大型文字/LOB欄位),必要時改用觸發器維護計數表。
  4. 分頁總筆數:優先用系統表估算,或快取 COUNT(*) 結果 (如 Redis),避免每頁查詢重複掃描。

結論

千萬筆實測證實:COUNT(*) = COUNT(PK) >> COUNT(定長數值) > COUNT(變長文字) > COUNT(LOB)。選對寫法、配合索引覆蓋、善用系統中繼資料,是大數據量下 COUNT 效能優化的鐵三角。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved