假設表 T(ID PK, VALUE)。
SELECT * FROM T WHERE ROWNUM <= 10
MINUS
SELECT * FROM T WHERE ROWNUM <= 5;
執行兩次全表/索引掃描,再排序差集。
SELECT ID, VALUE
FROM (
SELECT ID, VALUE, ROWNUM RN
FROM T
WHERE ROWNUM <= 10
)
WHERE RN > 5;
WHERE ROWNUM <= 10 讓 Oracle **提前停止** 掃描 (COUNT STOPKEY)。RN > 5 取得第 6-10 筆。WHERE ROWNUM <= :end_row 內層,WHERE RN > :start_row 外層。場景:主表 T1(ID PK, VALUE),對照表 T2(VALUE)。
-- IN
SELECT * FROM T1 WHERE VALUE IN (SELECT VALUE FROM T2);
-- NOT IN
SELECT * FROM T1 WHERE VALUE NOT IN (SELECT VALUE FROM T2);
執行計劃多為 FILTER + 子查詢逐行比對,資料量萬級以上極慢。
-- 替代 IN
SELECT T1.ID, T1.VALUE
FROM T1, T2
WHERE T1.VALUE = T2.VALUE(+) -- (+) 標示右表外連
AND T2.VALUE IS NOT NULL; -- 過濾掉無匹配行
-- 替代 NOT IN
SELECT T1.ID, T1.VALUE
FROM T1, T2
WHERE T1.VALUE = T2.VALUE(+)
AND T2.VALUE IS NULL; -- 保留無匹配行
(+) 僅支援單表外連,複雜條件建議改用 ANSI SQL: LEFT JOIN T2 ON T1.VALUE = T2.VALUE。| 寫法 | 耗時 | 計劃 |
|---|---|---|
| NOT IN 子查詢 | ~30 分鐘 | FILTER + NESTED LOOPS |
| LEFT JOIN + IS NULL | ~3 秒 | HASH JOIN RIGHT OUTER |
分頁用 ROWNUM 內聯視圖 + STOPKEY;NOT IN/IN 大量資料**必改外連接**,效能提升百倍且規避 NULL 陷阱。