在上一篇中,建立了閱讀執行計畫的「方向感」,學會透過箭頭粗細找出塞車路段。順著箭頭一路往右追溯到最源頭,就會看到 SQL Server 是如何進入資料庫「拿資料」,這一步至關重要,因為資料庫系統最大的效能瓶頸往往在於磁碟 I/O(資料讀寫),是在「精準尋找」還是在「盲目翻找」,決定了這個查詢是只要 0.1 秒,還是要跑 10 分鐘。
在執行計畫的最右側,最常看見的資料存取運算子有這幾種:
1.理想的境界:Index Seek

- 白話比喻: 就像查字典時,利用部首或注音索引,直接翻到你要的那一頁。
- 背後意義: 這是效能最好的存取方式。代表 SQL Server 完美利用了 B-Tree 索引結構,精確定位到符合
WHERE條件的資料列。看到這個圖示通常代表你的索引設計順利發揮了作用。
2.尷尬的中間地帶:Index Scan

- 白話比喻: 不用翻整本字典,但把字典的「整個附錄/整個目錄」從頭到尾看了一遍。
- 背後意義: 看到 "Index" 這個字或許會覺得令人安心,但請注意後面的 "Scan"。這代表查詢條件無法讓 SQL Server 縮小搜尋範圍,只好把整個索引從頭到尾掃了一遍。
- 優化建議:
- 改善查詢條件(避免索引失效): 這是最常見的「索引殺手」,例如在欄位上套函數(如
WHERE YEAR(created_at) = 2026),或發生型別隱含轉換(字串比對數字欄位),可以改成對索引友善的寫法,例如:WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01',讓 SQL Server 能切換回 Index Seek。 - 建立或調整 Composite Index(複合索引): 把常常一起出現在
WHERE、ORDER BY的欄位組合進同一個索引,且要注意欄位順序。 - 減少回傳欄位: 盡量避免
SELECT *,只取真正需要的欄位,有助於讓 Optimizer 選擇更精準的索引。
- 改善查詢條件(避免索引失效): 這是最常見的「索引殺手」,例如在欄位上套函數(如
3.效能的紅燈:Table Scan / Clustered Index Scan
- 白話比喻: 為了找書裡的一句話,從第一頁逐字逐句讀到最後一頁。
- 背後意義: 這是最需要優先處理的狀況,代表完全沒有可用的索引,或查詢條件根本繞過了索引。SQL Server 必須把整張表掃描一遍,一筆一筆核對。
- 優化建議:
- 建立索引: 最直接的解法,可以先參考 Execution Plan 上方黃色字體的 Missing Index 提示來建立 Non-Clustered Index,這通常能立竿見影。
- 檢查資料選擇性(Selectivity): 如果你的
WHERE條件篩出來的資料佔了整張表的 20%–30% 以上,SQL Server 會認為「既然都要抓這麼多資料,不如直接掃整張表比較快」;此時加索引沒用,需要檢討的是查詢邏輯本身。 - 更新統計資料: 執行
UPDATE STATISTICS或sp_updatestats,有時候是資料庫的統計資訊太舊,導致 Optimizer 誤判,放著好好的索引不用跑去掃表。 - 檢查
NOLOCK或 Hint 干擾: 確認程式碼中是否有不必要的查詢提示(Hint)強制改變了 SQL Server 的預設行為。
4.隱藏的效能殺手:Key Lookup

- 白話比喻: 用目錄找到了頁碼,但發現那頁只有大綱,還得跑去另一本詳細版的手冊裡翻出完整內容。
- 背後意義:有時候明明看到計畫裡有 Index Seek,查詢卻還是很慢?原因是現有索引只包含部分欄位。SQL Server 找到條件相符的資料列後,還要再「回表(回 Clustered Index)」去撈
SELECT中缺乏的其他欄位,造成龐大的額外 I/O。 - 優化建議:
- 加上 INCLUDE 欄位(涵蓋索引 Covering Index): 這是最常見且有效的解法。把
SELECT清單中非索引的欄位,加到 Non-Clustered Index 的INCLUDE裡,SQL Server 就不需要再回表了。
- 加上 INCLUDE 欄位(涵蓋索引 Covering Index): 這是最常見且有效的解法。把
-- 原本會造成 Key Lookup 的索引
CREATE INDEX IX_Orders_CustomerId ON Orders (CustomerId);
-- 優化:加上 INCLUDE,把常查的欄位一起放進去
CREATE INDEX IX_Orders_CustomerId ON Orders (CustomerId)
INCLUDE (OrderDate, TotalAmount, Status);
- 減少
SELECT欄位: 如果 Key Lookup 次數極高,最快的解法是拿掉不必要的SELECT欄位,減少需要回表的負擔。 - 合併重複的索引: 如果同一張表有多個相似的索引,各自
INCLUDE不同的欄位,可以考慮合併成一個較完整的索引,降低維護成本與回表機率。
- 減少
搞定了資料讀取的第一關,手上就有了最精簡的資料集;但在關聯式資料庫中,經常需要把多張表的資料拼湊在一起。這時候,SQL Server 會派誰上場呢?
在下一篇,我們將為你大解密三種截然不同,卻各有千秋的 Join 運算子!













