首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

SQL 多表關聯查詢:四種寫法效能對比與最佳實務

     編輯:MySQL 資料庫相關知識

多表關聯查詢寫法直接影響效能。本文展示四種常見寫法(隱性 JOIN、子查詢、變數預設、IN 子查詢),分析優缺點與適用場景。

場景設定

  • order_info:訂單主表
  • ivrlog4ivrdlvinst:IVR 通話記錄
  • delivery_info:配送資訊
  • 需求:依日期、技能組、服務單號關聯三表

方法一:隱性 INNER JOIN(舊式逗號語法)

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

❌ 缺點:舊語法可讀性差、易寫錯、彙總函數誤用、最佳化器難優化。

方法二:相關子查詢(Correlated Subquery)

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)

✅ 修正了彙總函數錯誤,但相關子查詢效能問題仍在。

方法四:顯性 JOIN + IN 子查詢(推薦)

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 需要的欄位,避免 SELECT *
  • ✅ 日期轉換 CONVERT 可能導致索引失效,考慮用範圍查詢 instime >= @date2 AND instime < DATEADD(day,1,@date2)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved