關於 WHERE 子句條件順序是否影響性能,歷來有三種觀點:
ALL_ROWS CBO)。官方文檔從 8i 到 11g 均無明確說明條件順序影響性能。本文通過三組實驗給出結論。
-- 9i / 10g / 11g 均一致
SELECT 'ok' FROM dual WHERE 1/0 = 1 AND 1 = 2; -- 不報錯(右側 1=2 先判為 FALSE,短路)
SELECT 'ok' FROM dual WHERE 1 = 2 AND 1/0 = 1; -- ORA-01476: divisor is equal to zero
-- 證明:解析器按從右到左順序評估條件表達式
DROP TABLE temp;
CREATE TABLE temp (t1 VARCHAR2(10), t2 VARCHAR2(10));
INSERT INTO temp VALUES ('zm','abcde');
INSERT INTO temp VALUES ('sz','1');
INSERT INTO temp VALUES ('sz','2');
COMMIT;
-- 條件順序 1:數字轉換在右
SELECT * FROM temp WHERE TO_NUMBER(t2) > 1 AND t1 = 'sz'; -- 成功(先過濾 t1='sz',再轉換 t2)
-- 條件順序 2:數字轉換在左
SELECT * FROM temp WHERE t1 = 'sz' AND TO_NUMBER(t2) > 1; -- ORA-01722: invalid number
-- 9i 確認:運行時也按從右到左過濾,導致 'abcde' 被 TO_NUMBER 報錯
10g 行為變化:兩條語句均不報錯,優化器自動調整過濾順序(將 t1='sz' 先應用),體現 CBO 智能重排。
構建帶副作用的函數觀察調用順序:
CREATE OR REPLACE FUNCTION f1(v_in VARCHAR2) RETURN VARCHAR2 IS
BEGIN DBMS_OUTPUT.PUT_LINE('exec F1'); RETURN v_in; END;
/
CREATE OR REPLACE FUNCTION f2(v_in VARCHAR2) RETURN VARCHAR2 IS
BEGIN DBMS_OUTPUT.PUT_LINE('exec F2'); RETURN v_in; END;
/
SET SERVEROUTPUT ON
SELECT 1 FROM dual WHERE f1('1')='1' AND f2('1')='1';
-- 輸出:
-- exec F2
-- exec F1
-- 證明:10g/11g 運行時過濾仍遵循從右到左順序
| 維度 | 結論 |
|---|---|
| 語法解析 | 從右到左(短路求值) |
| 9i 運行時過濾 | 從右到左(隱式轉換報錯可證) |
| 10g/11g+ 運行時過濾 | 從右到左(函數調用順序可證) |
| CBO 執行計劃生成 | 與條件書寫順序無關,基於統計信息自動選擇最優訪問路徑 |
| 性能影響 | 無實質性能差異,優化器會重排謂詞順序 |
WHERE TO_NUMBER(col) > 1 寫法極危險,應修正數據模型或使用函數索引。WHERE (A=1 AND B=2) OR (C=3)。DBMS_STATS.GATHER_TABLE_STATS,讓 CBO 自動決策。