多表關聯查詢寫法直接影響效能。本文展示四種常見寫法(隱性 JOIN、子查詢、變數預設、IN 子查詢),分析優缺點與適用場景。
order_info:訂單主表ivrlog4ivrdlvinst:IVR 通話記錄delivery_info:配送資訊SELECT *
FROM order_info AS a, ivrlog4ivrdlvinst AS b
WHERE a.saleorder = b.ext1_skill
AND b.start_date = @date1
AND b.se_id = '55'
AND b.ext1_skill <> ''
AND CONVERT(varchar(10), a.instime, 112) = @date2
AND MAX(a.instime) -- ❌ 語法錯誤:彙總函數不可直接用於 WHERE
❌ 缺點:舊語法可讀性差、易寫錯、彙總函數誤用、最佳化器難優化。
SELECT *
FROM order_info AS a
WHERE a.saleorder = (
SELECT b.ext1_skill
FROM ivrlog4ivrdlvinst AS b
WHERE b.start_date = @date1
AND b.se_id = '55'
AND b.ext1_skill <> ''
)
AND CONVERT(varchar(10), MAX(a.instime), 112) = @date2 -- ❌ 同樣錯誤
⚠️ 風險:外層表大時,子查詢會逐列執行,效能極差(參見文章 48187)。
DECLARE @date1 VARCHAR(20), @date2 VARCHAR(20)
SET @date1 = '20100812'
SET @date2 = '2010-08-12'
SELECT *
FROM order_info AS a
WHERE a.saleorder = (
SELECT b.ext1_skill
FROM ivrlog4ivrdlvinst AS b
WHERE b.start_date = @date1
AND b.se_id = '55'
AND b.ext1_skill <> ''
)
AND CONVERT(varchar(10), a.instime, 112) = @date2
AND a.instime = (SELECT MAX(instime) FROM order_info WHERE saleorder = a.saleorder)
✅ 修正了彙總函數錯誤,但相關子查詢效能問題仍在。
SELECT b.caller, b.start_date, b.start_time, b.ext1_skill,
c.deliveryno, c.destroyresult, c.deliverydate, c.deliverytime,
c.arrangetime, c.driverphone, c.drivermobile,
a.servicedate, a.servicetime, a.workertel
FROM order_info AS a
JOIN ivrlog4ivrdlvinst AS b ON a.saleorder = b.ext1_skill
JOIN delivery_info AS c ON a.saleorder = c.deliveryno
WHERE b.start_date = @date1
AND b.se_id = '55'
AND b.ext1_skill <> ''
AND CONVERT(varchar(10), a.instime, 112) = @date2
ORDER BY b.start_date DESC, b.start_time DESC
| 寫法 | 可讀性 | 效能 | 建議 |
|---|---|---|---|
| 隱性 JOIN (逗號) | 低 | 不穩定 | ❌ 棄用 |
| 相關子查詢 | 中 | 外層大表時極差 | ⚠️ 僅小表或 EXISTS 適合 |
| 顯性 JOIN (ANSI-92) | 高 | 最佳化器最友善 | ✅ 首選 |
| IN / EXISTS 子查詢 | 中 | 視最佳化器轉換 | ✅ 適合半連接場景 |
JOIN ... ON 顯性語法SELECT *CONVERT 可能導致索引失效,考慮用範圍查詢 instime >= @date2 AND instime < DATEADD(day,1,@date2)