WHERE子句与ON子句写条件:哪种查询更标准且最优?
两个INNER JOIN SQL查询的标准性与性能对比
先看你给出的两个查询:
查询1:
SELECT p.* FROM posts p JOIN favorites f ON p.id = f.post_id WHERE f.user_id = ?
查询2:
SELECT p.* FROM posts p JOIN favorites f ON p.id = f.post_id AND f.user_id = ?
嘿,这个问题问得挺细致的!直接给你核心结论:
- 这两个查询都是完全符合标准SQL规范的,不存在谁不标准的问题
- 在绝大多数主流关系型数据库(比如MySQL、PostgreSQL、SQL Server、Oracle)中,它们的性能表现完全一致
为什么性能没区别?
数据库的查询优化器可不是吃素的——对于INNER JOIN来说,把f.user_id = ?放在ON子句里,还是放在WHERE子句里,优化器会自动识别这两种写法的逻辑等价性,最终生成的执行计划完全相同。它会自动选择成本最低的执行路径(比如先过滤favorites表中符合user_id的记录再关联,还是先关联再过滤?优化器会自己算),不会因为写法不同而有区别。
写法偏好:看可读性和场景
这俩写法的差异更多是代码风格和可读性的问题:
- 查询1的写法更传统:把表之间的关联条件(
p.id = f.post_id)放在ON,把结果集的过滤条件(f.user_id = ?)放在WHERE,逻辑划分非常清晰,看代码的人能一眼区分“哪些是表关联的规则”,“哪些是最终要保留的数据的规则”。 - 查询2的写法是把过滤条件和关联条件合并到
ON里,相当于在JOIN的过程中就过滤掉不符合的favorites记录。这种写法在LEFT JOIN场景下会有本质区别(比如LEFT JOIN时,放ON里不会过滤主表的记录,放WHERE里会把主表中没有匹配的记录也过滤掉),但在INNER JOIN的场景下,只是风格不同而已。
关键提醒:LEFT JOIN才会有结果差异!
如果把这里的JOIN改成LEFT JOIN,那这两个查询的返回结果就完全不一样了:
- 查询1的
WHERE f.user_id = ?会把所有favorites中没有匹配的posts记录过滤掉,相当于把LEFT JOIN变成了INNER JOIN - 查询2的
ON ... AND f.user_id = ?会保留所有posts记录,只是关联不上符合条件的favorites时,f的字段会显示为NULL
不过回到你的问题,既然是INNER JOIN,两种写法随便选哪种都可以,完全不用担心标准性和性能问题,跟着团队的代码风格偏好走就行。
内容的提问来源于stack exchange,提问作者Martin AJ
相关产品推荐
相关产品推荐

