非叢集索引如何實現「毫秒級查找」?本文從現象切入,結合 DBCC IND、DBCC PAGE 實測,揭示非叢集索引 **B-Tree 結構**、**Key + RID 儲存格式**、**書籤查詢** 完整鏈路。
查詢 WHERE Name = 'jjjjj' 走非叢集索引 idx_Person_Name:

關鍵觀察:Index Seek (NonClustered) 後接 RID Lookup(堆表)或 Key Lookup(叢集索引表)。
RID = FileID : PageID : SlotID,唯一定位堆表中某資料列的物理座標。
驗證函數:sys.fn_PhysLocFormatter(%%physloc%%)
SELECT ProductID, sys.fn_PhysLocFormatter(%%physloc%%) AS RID FROM dbo.Product;
輸出範例:(1:34941:0)、(1:34941:1) → 第 1 檔案、34941 頁、Slot 0/1。

DROP TABLE dbo.Person;
CREATE TABLE Person (ID INT IDENTITY, NAME CHAR(900)); -- 900 bytes 接近索引鍵上限
CREATE INDEX idx_Person_Name ON dbo.Person(Name);
DECLARE @ch INT = 97;
WHILE @ch <= 122 BEGIN
INSERT INTO dbo.Person VALUES (REPLICATE(CHAR(@ch), 5)); -- 'aaaaa', 'bbbbb'...
SET @ch += 1;
END


關鍵發現:
aaaaa, bbbbb...94000000 01000000 → PageID=0x94=148, FileID=1, Slot=0 = RID。
每筆記錄包含:Child Page MinKey + Child PageID + FileID,導航至下層頁面。

idx_Person_Name。Name='jjjjj',取出 **RID**。
5. **RID Lookup** 直接定位堆表資料頁讀取完整列(含未在索引的欄位)。
6. 輸出結果。
若查詢欄位全包含於索引鍵或 INCLUDE 欄位,**無需回基表**,執行計畫僅顯示 Index Seek,效能大幅提升。
CREATE INDEX idx_Person_Name_Cover ON dbo.Person(Name) INCLUDE (ID); -- 或其他查詢欄位
非叢集索引 = **有序 Key 陣列 + RID 指標**,B-Tree 導航 + RID Lookup 兩階段定位。理解 Key+RID 結構、善用 INCLUDE 建立覆蓋索引,是查詢調優核心技能。