如何高效实现表级Either-Or查询并优化执行性能
最优实现方案及性能优化建议
方案1:使用EXISTS实现Either-Or逻辑(性能最优)
该方案无需重复执行Parent表关联逻辑,且EXISTS自带短路求值特性,只要满足Son或Daughter任意一个条件就会停止校验,不会产生冗余计算,同时关联时可以直接命中Son和Daughter表的Pid索引,先通过Pid过滤再校验低区分度的wearing_glass条件,大幅减少待校验数据量。
SELECT p.* FROM ( SELECT Pid, ... FROM Parent JOIN Foreign1 ON ... LEFT JOIN Foreign2 ON ... ) p WHERE EXISTS ( SELECT 1 FROM Son s WHERE s.Pid = p.Pid AND s.son_wearing_glass ) OR EXISTS ( SELECT 1 FROM Daughter d WHERE d.Pid = p.Pid AND d.daughter_wearing_glass );
如果需要去重(同一个Pid同时满足Son和Daughter条件时只返回一次),该写法天然支持,不需要额外加UNION/ DISTINCT。
方案2:CTE复用Parent关联结果(适合需要保留UNION ALL逻辑的场景)
如果你的业务逻辑更适合拆分Son和Daughter的关联逻辑,可以用CTE缓存Parent关联后的结果,避免两次重复执行p子查询:
WITH parent_filtered AS ( SELECT Pid, ... FROM Parent JOIN Foreign1 ON ... LEFT JOIN Foreign2 ON ... ) SELECT p.* FROM parent_filtered p JOIN Son s ON p.Pid = s.Pid WHERE s.son_wearing_glass UNION ALL SELECT p.* FROM parent_filtered p JOIN Daughter d ON p.Pid = d.Pid WHERE d.daughter_wearing_glass;
如果需要去重,把UNION ALL改成UNION即可。
额外索引优化(可让性能再提升1~2个数量级)
针对低区分度的wearing_glass条件,你可以给Son和Daughter表建联合索引,关联和条件校验都可以直接走索引覆盖,无需回表:
-- Son表联合索引:先通过Pid定位,直接在索引中判断wearing_glass条件 CREATE INDEX idx_son_pid_wearing ON Son(Pid, son_wearing_glass); -- Daughter表联合索引 CREATE INDEX idx_daughter_pid_wearing ON Daughter(Pid, daughter_wearing_glass);
方案对比
- 最初的写法:先全表扫Son/Daughter的wearing_glass条件,返回大量低区分度结果后再和Parent关联,无效计算多,性能最差
- 拆分UNION ALL重复执行p子查询的写法:关联逻辑高效但Parent关联重复计算,资源消耗翻倍
- 上述EXISTS方案:兼具关联效率和无冗余计算的优势,是当前场景的最优解
内容的提问来源于stack exchange,提问作者Jeb50
相关产品推荐
相关产品推荐

