SELECT * FROM table1
WHERE EXISTS (
SELECT * FROM table2
WHERE id >= 30000 AND table1.uuid = table2.uuid
);
table1:10 萬行table2:100 萬行EXPLAIN:DEPENDENT SUBQUERY,外層全表掃描 table1,每行驅動子查詢SELECT * FROM table1 INNER JOIN table2 USING (uuid) WHERE table2.id >= 30000;
EXPLAIN:SIMPLE,優化器先過濾 table2.id >= 30000,再 Hash Join / Nested Loop| 維度 | EXISTS 關聯子查詢 | INNER JOIN |
|---|---|---|
| 執行策略 | 外層驅動,逐行查找 | 優化器自由選擇連接順序/算法 |
| 過濾下推 | 困難(子查詢內部過濾) | 自然下推(WHERE 直接作用於驅動表) |
| 索引利用 | 被動 | 主動(可用 Hash Join / Batched Key Access) |
| 結果集 | 去重(EXISTS 語義) | 可能重複(需 DISTINCT 或業務保證唯一) |
subquery_to_derived/semijoin),但手工改寫更可控-- 1. 原查詢 EXPLAIN EXPLAIN SELECT ... EXISTS ...; -- 2. 改寫 JOIN EXPLAIN EXPLAIN SELECT ... INNER JOIN ...; -- 3. 結果集對比(確認語義等價) SELECT COUNT(*) FROM (原查詢) t1; SELECT COUNT(DISTINCT uuid) FROM (JOIN查詢) t2; -- 若一致,語義等價
**關聯子查詢(EXISTS/IN)是優化器的盲區**,手工改寫為 **JOIN 讓優化器擁有完整統計信息、自由選擇最優路徑**。养成「見關聯子查詢,試 JOIN 改寫」的肌肉記憶,性能提升往往超預期。