「慎用 IN、禁用 NOT IN、避開 <>、拒絕 IS NULL、謹慎通配符、優先 UNION ALL」
-- 低效:IN 子查詢
SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE vip = 'Y');
-- 高效:EXISTS 相關子查詢
SELECT * FROM orders o WHERE EXISTS (SELECT 1 FROM customers c WHERE c.id = o.customer_id AND c.vip = 'Y');
-- 危險:NOT IN (含 NULL 時邏輯錯誤 + 全表掃描)
SELECT * FROM orders WHERE customer_id NOT IN (SELECT id FROM customers WHERE status = 'INACTIVE');
-- 安全高效:NOT EXISTS
SELECT * FROM orders o WHERE NOT EXISTS (SELECT 1 FROM customers c WHERE c.id = o.customer_id AND c.status = 'INACTIVE');
-- 替代:Left Outer Join + IS NULL
SELECT o.* FROM orders o LEFT JOIN customers c ON o.customer_id = c.id AND c.status = 'INACTIVE' WHERE c.id IS NULL;
NULL 時整體判斷為 UNKNOWN,導致邏輯錯誤;且無法使用索引,必然全表掃描。-- 低效:不等於永遠不走索引
SELECT * FROM accounts WHERE balance <> 0;
-- 高效:改寫為範圍查詢 (假設 balance >= 0)
SELECT * FROM accounts WHERE balance > 0;
-- 字串不等於
SELECT * FROM users WHERE status <> 'INACTIVE';
-- 改寫
SELECT * FROM users WHERE status > 'INACTIVE' OR status < 'INACTIVE';
<> 必觸發 Full Table Scan。> / < / BETWEEN / IN 等範圍條件,即可走索引範圍掃描。WHERE col IS NULL 無法走單欄索引。-- 解決方案
-- 1. 設計階段:NOT NULL 約束 + 預設值
ALTER TABLE orders MODIFY status DEFAULT 'NEW' NOT NULL;
-- 2. 函數索引 (11g+)
CREATE INDEX idx_orders_status_nvl ON orders (NVL(status, 'NULL_PLACEHOLDER'));
-- 查詢: WHERE NVL(status, 'NULL_PLACEHOLDER') = 'NULL_PLACEHOLDER'
-- 3. 位圖索引 (低基數欄位、DW 環境)
CREATE BITMAP INDEX idx_orders_status_bmp ON orders (status);
-- 位圖索引包含 NULL 值
-- 低效:前導通配符
SELECT * FROM customers WHERE phone LIKE '%5400%';
-- 高效:業務邏輯重構
-- 若 phone 格式固定 'X-5400-XXXX' 或 'B-5400-XXXX'
SELECT * FROM customers WHERE phone LIKE 'X-5400-%' OR phone LIKE 'B-5400-%';
'ABC%') 可走索引範圍掃描。-- 低效:UNION 會 Sort + Unique
SELECT * FROM current_orders UNION SELECT * FROM history_orders;
-- 高效:UNION ALL 直接合併 (業務確認無重複)
SELECT * FROM current_orders UNION ALL SELECT * FROM history_orders;
EXPLAIN PLAN / DBMS_XPLAN.DISPLAY_CURSOR。DBMS_STATS.GATHER_TABLE_STATS。USER_INDEXES / USER_IND_COLUMNS。