嵌套查询不能在不同层级执行不同过滤条件,条件应按作用位置放置:连接用on、筛选用where、抽象用cte;left join右表条件须写在on中,否则退化为inner join;多层权限继承必须用with recursive预展开;相关子查询性能差,应优先改写为join。

嵌套查询不能“在不同层级执行不同过滤条件”
SQL里没有“让子查询自己按外层参数动态调整逻辑”的机制。所谓“不同层级过滤”,其实是把条件放在该起作用的位置:连接关系用ON,最终结果筛选用WHERE,中间状态抽象用CTE。子查询本身不接收参数、不响应外部变化,它只是被外层调用的一段静态SQL。
LEFT JOIN后右表条件必须写进ON,不能放WHERE
这是线上最常踩的坑。一旦把右表字段条件(比如o.status = 'paid')写在WHERE里,LEFT JOIN就退化成INNER JOIN,所有左表无匹配或右表不满足条件的行全被剔除。
- 错误写法:
SELECT u.name, o.order_id FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.status = 'paid' - 正确写法:
SELECT u.name, o.order_id FROM users u LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'paid' - 验证方式:执行
EXPLAIN,若Extra列出现Using where且涉及右表字段,说明逻辑已变异
多层权限继承必须用WITH RECURSIVE预展开
EXISTS子查询无法递归。当角色A继承B、B继承C时,靠两层JOIN查不出C的权限。必须先用WITH RECURSIVE算出用户最终拥有的全部角色ID集合,再拿这个集合去关联权限表。
- 递归CTE必须包含非递归部分(如
SELECT role_id FROM role_user WHERE user_id = 123)和递归部分(UNION SELECT ... FROM role_inherit JOIN user_roles ...),缺一不可 - PostgreSQL默认递归深度100,长链需加
SEARCH DEPTH FIRST BY role_id SET ordercol并配合WHERE ordercol - 结果必须加
DISTINCT——继承路径可能导致同一资源被多次匹配
相关子查询性能敏感,优先改写为JOIN
像EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = @status)这类写法,如果users表有10万行,子查询就会执行10万次。这不是语法错,是执行计划层面的放大。
- 检查
EXPLAIN输出:若子查询type为ALL且无ref或eq_ref,大概率缺索引或应改写 -
orders.user_id必须有索引,否则每次都是全表扫描 - 更稳的替代方案是先用
CTE或临时表物化符合条件的订单集合,再与users做JOIN
ON)、结果筛选(WHERE),还是中间状态(CTE)”。写错位置,数据就错;索引没建对,性能就崩。











