某專案遇到效能瓶頸,原始 SQL 執行 203 筆資料卻耗時 12 秒:
SELECT SO_Order.fdate, SO_Order.fsn
FROM so_order
INNER JOIN so_orderitem ON CHARINDEX(so_Orderitem.fid, SO_Order.fid) >= 1
WHERE so_order.FOrderDate = '2015-09-06'
資料分布:
so_order 當日 24 筆,fid 為逗號分隔字串(1-2 個 ID)so_orderitem 總筆數 414,154 筆雖然 so_order 驅動 so_orderitem 的 Nested Loops 邏輯正確,但瓶頸在於 so_orderitem 進行索引掃描而非索引查找。原因在於 CHARINDEX 函數導致聯結條件非 SARGable,優化器無法利用 so_orderitem.fid 索引。

將 so_order.fid 逗號分隔字串拆分為兩行,再與 so_orderitem 進行等值聯結,使優化器能使用索引查找:
;WITH x0 AS (
-- 第一段:逗號前的 ID
SELECT fdate, fsn,
LEFT(fid, CASE WHEN CHARINDEX(',', fid, 1) = 0 THEN 0 ELSE CHARINDEX(',', fid, 1) - 1 END) AS fid
FROM so_order WHERE FOrderDate = '2015-09-06'
UNION ALL
-- 第二段:逗號後的 ID
SELECT fdate, fsn,
RIGHT(fid, LEN(fid) - CHARINDEX(',', fid, 1)) AS fid
FROM so_order WHERE FOrderDate = '2015-09-06'
)
SELECT SO_Order.fdate, SO_Order.fsn
FROM x0 so_order
INNER JOIN so_orderitem ON so_Orderitem.fid = SO_Order.fid
改寫後執行計畫顯示 so_orderitem 走索引查找,邏輯讀取大幅下降:


延伸思考:長期解決方案應考慮資料模型正規化,將多值欄位拆分為關聯表,從根源消除此類效能隱患。