首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL 字段拆分優化實戰:將 CHARINDEX 連接改寫為索引查找,效能提升 40 倍

     編輯:關於SqlServer

案例背景:一條 12 秒的慢查詢

某專案遇到效能瓶頸,原始 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 索引。

原始執行計畫:索引掃描

優化策略:字段拆分 + UNION ALL 轉為等值聯結

將 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

效能對比:從 12 秒降至 300 毫秒

改寫後執行計畫顯示 so_orderitem 走索引查找,邏輯讀取大幅下降:

改寫後客戶端回饋:耗時大幅縮短

優化後執行計畫:索引查找

核心原理與適用場景

  1. 將非 SARGable 條件轉為 SARGable:函數運算 → 等值比較,啟用索引查找
  2. 適用於分隔符號固定、拆分邏輯確定的字串欄位
  3. 資料量大、聯結頻繁的場景收益最大

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

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved