一般檢視表 只是儲存查詢定義,不佔用儲存空間,每次查詢即時運算。索引檢視表 透過建立唯一叢集索引,將結果集**實體化** 儲存於資料庫,並在基底表異動時自動維護,極大提升彙總查詢效能。本文完整示範建立流程、必要條件、效能對比與權衡考量。
檢視表定義必須滿足所有條件,才能建立索引:
WITH SCHEMABINDING:綁定結構描述,防止基底表結構變更導致檢視失效schema.table)SELECT *,必須明確列出欄位COUNT_BIG(*) 而非 COUNT(*)OUTER JOIN、DISTINCT、TOP、UNION、子查詢、ORDER BY 等ANSI_NULLS ON, ANSI_PADDING ON, ANSI_WARNINGS ON, CONCAT_NULL_YIELDS_NULL ON, QUOTED_IDENTIFIER ON, NUMERIC_ROUNDABORT OFF
CREATE TABLE SalesHistory (
SaleID INT IDENTITY(1,1),
Product VARCHAR(30),
SaleDate SMALLDATETIME,
SalePrice MONEY
);
DECLARE @i SMALLINT = 1;
WHILE @i <= 10000
BEGIN
INSERT INTO SalesHistory (Product, SaleDate, SalePrice)
VALUES ('Computer', DATEADD(MM, @i, '20060310'), DATEPART(MS, GETDATE()) + @i + 57);
INSERT INTO SalesHistory (Product, SaleDate, SalePrice)
VALUES ('BigScreen', DATEADD(MM, @i, '20060302'), DATEPART(MS, GETDATE()) + @i + 13);
INSERT INTO SalesHistory (Product, SaleDate, SalePrice)
VALUES ('PoolTable', DATEADD(MM, @i, '20070211'), DATEPART(MS, GETDATE()) + @i + 29);
SET @i = @i + 1;
END
-- 共 30,000 列
CREATE VIEW vw_SalesByProduct
AS
SELECT Product, COUNT_BIG(*) AS ProductCount, SUM(SalePrice) AS TotalSales
FROM dbo.SalesHistory
GROUP BY Product;
查詢 WHERE Product = 'Computer' → **表格掃描**,掃描 30,000 列。
-- 必須先設定 Session 選項 (SSMS 預設通常已符合)
SET ANSI_NULLS ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
GO
CREATE VIEW dbo.vw_SalesByProduct_Indexed
WITH SCHEMABINDING
AS
SELECT Product,
COUNT_BIG(*) AS ProductCount,
SUM(ISNULL(SalePrice, 0)) AS TotalSales -- ISNULL 確保確定性
FROM dbo.SalesHistory
GROUP BY Product;
GO
-- 建立唯一叢集索引 (實體化關鍵步驟)
CREATE UNIQUE CLUSTERED INDEX idx_SalesView ON vw_SalesByProduct_Indexed (Product);
GO
EXEC sp_spaceused 'vw_SalesByProduct_Indexed';
/* 結果範例:
name rows reserved data index_size unused
vw_SalesByProduct_Indexed 3 16 KB 8 KB 8 KB 0 KB
*/
僅 3 列 (三種產品),佔用 16 KB,確認已實體化。
-- 一般檢視表:表格掃描
SET STATISTICS IO ON;
SELECT Product, TotalSales, ProductCount
FROM vw_SalesByProduct
WHERE Product = 'Computer';
-- Table 'SalesHistory'. Scan count 1, logical reads 124...
-- 索引檢視表:叢集索引搜尋
SELECT Product, TotalSales, ProductCount
FROM vw_SalesByProduct_Indexed
WHERE Product = 'Computer';
-- Table 'vw_SalesByProduct_Indexed'. Scan count 1, logical reads 3...
邏輯讀從 124 降至 3,效能提升 ~40 倍。
| 面向 | 一般檢視表 | 索引檢視表 |
|---|---|---|
| 查詢效能 (彙總/聯集) | 即時運算,大表慢 | 預先計算,極快 |
| 儲存空間 | 無 | 佔用資料/索引頁面 |
| DML 影響 (INSERT/UPDATE/DELETE) | 無額外成本 | **每筆異動需同步維護索引**,增加寫入延遲 |
| 鎖定/封鎖風險 | 低 | 較高 (索引維護需鎖定) |
| 適用場景 | 頻繁異動、少量查詢、臨時報表 | **讀多寫少**、大量彙總、儀表板、資料倉庫維度查詢 |
SELECT * FROM vw_SalesByProduct_Indexed WITH (NOEXPAND) WHERE Product = 'Computer';
強制使用索引檢視表,即使查詢優化器判斷展開較佳sys.dm_db_index_operational_stats 觀察 leaf_insert_count, leaf_delete_count, leaf_update_count索引檢視表是 SQL Server **「以空間換時間、以寫入換讀取」** 的利器。關鍵在於:
SCHEMABINDING, COUNT_BIG, 確定性...)善用索引檢視表,能讓複雜的多表彙總報表從「秒級」進入「毫秒級」,是資料倉庫與 BI 報表層的核心加速技術之一。