2026-05/04~10技术问题处理
- [一.LEFT JOIN 与 INNER JOIN](#一.LEFT JOIN 与 INNER JOIN)
-
- [1. 原始业务场景](#1. 原始业务场景)
- [2. 原有错误 SQL](#2. 原有错误 SQL)
- [3. 存在问题 & 根因](#3. 存在问题 & 根因)
- [4. 分步优化 & 每步原因](#4. 分步优化 & 每步原因)
- [5. 最终正确 SQL](#5. 最终正确 SQL)
- [6. 配套索引](#6. 配套索引)
- [7. 二次拓展](#7. 二次拓展)
一.LEFT JOIN 与 INNER JOIN
1. 原始业务场景
左连接:以左表为主表,保留主表所有数据,根据连接条件匹配右表数据,匹配成功直接回显,匹配失败即为null.
内连接: 保留符合连接条件的数据。
2. 原有错误 SQL
sql
SELECT COUNT(task.id) FROM pro_inspect_await_instance_task task LEFT JOIN pro_inspect_product_submit submit
ON task.product_submit_id = submit.id WHERE submit.status <= 10
3. 存在问题 & 根因
- 逻辑错误:LEFT JOIN 左连接后,WHERE submit.status <=10 会把 submit为NULL 的数据全部过滤,左连接变相变成内连接,等价于内连接;
- 计数冗余:COUNT(task.id) 主键非空,和 COUNT() 效果一致,但优化器对 COUNT() 优化更好;
- 无索引:关联字段、过滤字段无索引,大表全表扫描性能差。
4. 分步优化 & 每步原因
- 把 submit 过滤条件从 WHERE 移到 JOIN 的 ON 后面
原因:ON 后过滤只过滤关联匹配的数据,不会删掉主表 task 不匹配的数据,保留左连接语义; - COUNT(task.id) 改为 COUNT(*)
原因:主键非空,语义等价,数据库优化器处理更高效; - 给关联字段、状态字段建立联合索引
原因:避免全表扫描,走索引快速过滤 + 关联。
5. 最终正确 SQL
sql
-- 保留主表所有数据,仅关联内过滤状态
SELECT COUNT(*) FROM pro_inspect_await_instance_task task LEFT JOIN pro_inspect_product_submit submit
ON task.product_submit_id = submit.id AND submit.status <= 10; -- 条件放ON里
6. 配套索引
sql
CREATE INDEX idx_submit_status_id ON pro_inspect_product_submit(status, id);
CREATE INDEX idx_task_submit_id ON pro_inspect_await_instance_task(product_submit_id);
7. 二次拓展
若业务本来就只需要两表都匹配数据,直接改用 INNER JOIN 更直观;大表可改用 EXISTS 半连接优化。