實例:根據電話或電子郵件查詢會員

假設我們有一個大型的 MemberOrders 表,記錄會員的訂單資料,欄位包含:

  • Phone
  • Email
  • OrderStatus
  • CreatedAt
  • MemberId

現在有一個功能:使用者輸入電話或電子郵件其中之一,系統需要查詢「已完成」的訂單,並找出對應的會員 ID。

因此後端常會送出這個查詢:

SELECT
	MemberId
FROM MemberOrders
WHERE OrderStatus = 'Completed' AND Phone = '0912345678'

又或是以 email 查詢:

SELECT
	MemberId
FROM MemberOrders
WHERE OrderStatus = 'Completed' AND Email = 'test@gmail.com'

查詢特性是:

  • 條件為 Phone 或 Email 二擇一
  • 需要篩選 OrderStatus
  • 最終只回傳 MemberId

如果資料表沒有索引,資料庫必須掃描整張表。

若只建立一個 (Phone, Email) 的複合索引,當查詢使用 Email 時,索引順序並不符合查詢條件,資料庫可能仍需掃描大量資料。

較佳做法是建立兩個非叢集索引:

CREATE NONCLUSTERED INDEX IX_MemberOrders_Phone_Status_CreatedAt
ON dbo.MemberOrders (Phone, OrderStatus)
INCLUDE (MemberId);
 
CREATE NONCLUSTERED INDEX IX_MemberOrders_Email_Status_CreatedAt
ON dbo.MemberOrders (Email, OrderStatus)
INCLUDE (MemberId);

這樣,當查詢使用 Phone 時,資料庫可以透過第一個索引進行 Index Seek;當使用 Email 時,則使用第二個索引。由於索引包含 MemberId,查詢可以在索引內完成,不需要 Key Lookup。

這種設計讓查詢計畫穩定、可預期,且在資料量持續成長時仍能維持良好效能。