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

SQL Server COUNT(*) vs COUNT(1) vs COUNT(欄位) 深度解析:執行原理、效能迷思與索引選擇策略

     編輯:關於SqlServer

最常用的聚合函數 COUNT 三種寫法到底有何不同?本文從**運算邏輯**、**執行計畫**、**索引選擇機制**三維度徹底釐清,打破「COUNT(1) 比 COUNT(*) 快」的迷思。

核心邏輯:計算「非 NULL 運算式」的列數

COUNT(運算式) 會逐列評估運算式,**非 NULL 才計數**。

  • COUNT(*):特殊語法,直接計算列數,**不評估任何欄位值**,永遠等於資料表列數。
  • COUNT(1) / COUNT('abc') / COUNT(常數):常數運算式永遠非 NULL,**結果等同 COUNT(*)**。
  • COUNT(欄位):評估該欄位值,**NULL 不計數**,非 NULL 計數。等同 SUM(CASE WHEN col IS NOT NULL THEN 1 ELSE 0 END)。

實證:NULL 測試

DECLARE @xx INT = NULL;
SELECT COUNT(@xx) FROM Sales.SalesOrderHeader;  -- 結果 0(所有列運算式皆 NULL)

COUNT(NULL) 結果 0

SELECT COUNT(*), COUNT(1), COUNT('anything') FROM Sales.SalesOrderHeader;  -- 結果完全相同

COUNT(*)/1/常數 結果相同

執行機制:最佳化器如何執行 COUNT(*)?

最佳化器需找出**「非 NULL 列數」**。策略:

  1. 尋找 **NOT NULL** 欄位(保證每列非 NULL)。
  2. 2. 若該欄位有索引,**選擇最窄索引**(最少頁面、最低 I/O)執行 **Index Scan/Seek** 計數。 3. 無 NOT NULL 索引則掃描叢集索引或堆表。

索引寬度影響實測

環境:Person.Address 表,移除所有非叢集索引。

  1. 建立 ModifiedDate (DATETIME, 8 bytes) 索引 → 執行計畫使用此索引。
    使用 DATETIME 索引
  2. 再建立 StateProvinceID (INT, 4 bytes) 索引 → **最佳化器自動切換至更窄的 INT 索引**。
    切換至 INT 索引

效能優化建議

  • COUNT(*) / COUNT(1) 無效能差異,寫碼習慣用 COUNT(*)(ANSI 標準、語意明確)。
  • 高頻 COUNT(*) 查詢表:**建立單一最窄 NOT NULL 欄位索引**(如 INT、BIGINT、CHAR(1)),大幅降低 I/O。
  • COUNT(可為 NULL 欄位) 需評估 NULL 語意,不可混淆為列數統計。
  • 大表近似計數可用 sys.dm_db_partition_stats.row_count 或 TABLESAMPLE。

總結

寫法語意執行計畫適用場景
COUNT(*)資料表列數(標準)掃描最窄 NOT NULL 索引通用列數統計
COUNT(1)等同 COUNT(*)同上個人習慣,無優勢
COUNT(col)col 非 NULL 列數掃描 col 索引或鍵查找特定欄位非空計數
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved