LEFT JOIN 執行順序:
ON 條件去右表匹配NULL 行WHERE 過濾
CREATE TABLE product(id INT PRIMARY KEY, amount INT);
CREATE TABLE product_details(id INT PRIMARY KEY, weight INT, exist INT);
INSERT INTO product VALUES (1,100),(2,200),(3,300),(4,400);
INSERT INTO product_details VALUES (2,22,0),(4,44,1),(5,55,0),(6,66,1);
SELECT * FROM product
LEFT JOIN product_details ON product.id = product_details.id
AND product_details.id = 2;
結果:左表 4 行全保留,只有 id=2 關聯上數據,其餘右表列全 NULL。
SELECT * FROM product
LEFT JOIN product_details ON product.id = product_details.id
WHERE product_details.id = 2;
結果:僅 1 行(id=2),因 WHERE 過濾掉了右表為 NULL 的行 → 退化為 INNER JOIN。
-- 找 product 中無對應 details 的行
SELECT p.* FROM product p
LEFT JOIN product_details d ON p.id = d.id
WHERE d.id IS NULL;
-- 結果:id=1,3
邏輯等價轉換(德摩根律):
-- ON 條件:p.id=d.id AND d.weight!=44 AND d.exist=0
-- WHERE d.id IS NULL
-- 等價於:
WHERE NOT EXISTS (SELECT 1 FROM product_details d
WHERE d.id=p.id AND d.weight!=44 AND d.exist=0)
-- 即:
WHERE d.id IS NULL OR d.weight=44 OR d.exist=1
當 SELECT * 時,WHERE 過濾後右表列可能非 NULL(如 d.weight=44 行被保留),導致結果與 ON+IS NULL 不同。只查左表列時兩者等價。
ONWHEREON 中混入純左表列條件(如 p.amount=100),移至 WHERE 更清晰EXPLAIN 觀察 type=ALL / Using where 判斷是否退化