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

SQL 語句突然變慢?外連接條件導致執行計劃劣化的排查與解決

     編輯:關於SqlServer

現象:一條 SQL 突然運行極慢

原本執行迅速的查詢,在加入一個看似無害的條件 member.site = 'test' 後,執行時間暴增。SQL 如下:

SELECT uidTable.column_value,
       first_name || ' ' || last_name,
       company,
       job_title,
       UPPER(member_level),
       UPPER(service_value)
FROM   (SELECT * FROM TABLE(CAST(MULTISET(SELECT b FROM bbb) AS Taaa) FROM dual)) uidTable,
       member
WHERE  uidTable.column_value = member.login_id(+)
AND    member.site = 'alibaba'
AND    member.site = 'test';

根本原因:外連接條件寫法導致連接順序反轉

原本驅動表是 uidTable(最多 1024 行),加入條件後,優化器將 member 表(600 萬行)作為驅動表,導致全表掃描,性能急劇下降。

為什麼外連接的連接順序會改變?因為外連接的連接順序並非由 COST 決定,而是由連接條件決定。當在外連接的表(member)上直接加上 member.site = 'test' 這樣的過濾條件時,外連接會隱性轉換為內連接,導致優化器重新排序。

執行計劃對比

問題計劃(外連接失效)

IdOperationNameRowsBytesCost
0SELECT STATEMENT1018722788155
1NESTED LOOPS1018722788155
2VIEW40726922411
3COLLECTION ITERATOR SUBQUERY FETCH
4TABLE ACCESS FULLDUAL407211
5TABLE ACCESS FULLBBB412872
6TABLE ACCESS BY INDEX ROWIDMEMBER1542
7INDEX UNIQUE SCANMEMBER_SITE_LID_PK41

修正後計劃(外連接生效)

將條件改為 member.site(+) = 'test' 後,外連接恢復正常,驅動表回到 uidTable,查詢瞬間完成。

核心知識點

  • Oracle 舊式外連接語法中,外連接表的所有過濾條件必須加上 (+),否則外連接會失效轉為內連接。
  • 外連接的連接順序由條件決定,而非成本優化器(CBO)自由選擇。
  • 使用 ANSI SQL-99 標準語法(LEFT JOIN ... ON)可避免此類陷阱,建議新代碼採用標準寫法。

解決方案總結

  1. 檢查所有外連接條件,確保外連接側的列在 WHERE 條件中均帶有 (+)。
  2. 或將查詢改寫為標準 LEFT JOIN 語法,將過濾條件移至 ON 子句中。
  3. 定期審查執行計劃,關注驅動表是否符合預期(小表驅動大表)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved