未使用ORDER BY时JOIN关联行的排序规则(PostgreSQL为例)
PostgreSQL中JOIN结果的关联行是否会相邻?
测试用表结构
user表
id | name ----+------- 1 | bob 2 | alice
user_group表
id | user_id | group ----+---------+------- 1 | 1 | g1 2 | 1 | g2 3 | 2 | g2 4 | 2 | g3
我们知道,执行不带ORDER BY的SELECT * FROM user时,无法保证每次返回的结果集顺序一致。那对于如下INNER JOIN查询:
SELECT user.name, user_group.group FROM user INNER JOIN user_group ON (user.id = user_group.user_id);
在PostgreSQL中,同一个用户的关联行是否一定会在结果集中相邻?比如只会出现以下两种符合“同用户行相邻”的情况(用户整体的排序、每个用户下分组的排序都无关紧要):
符合预期的结果示例1
name | group -------+------- bob | g1 bob | g2 alice | g2 alice | g3
符合预期的结果示例2
name | group -------+------- alice | g3 alice | g2 bob | g2 bob | g1
而不会出现用户行交叉的情况,比如:
name | group -------+------- bob | g1 alice | g2 bob | g2 alice | g3
结论:没有任何保证
PostgreSQL的查询优化器会根据数据分布、索引状态、可用的连接算法等因素选择最优执行计划,结果集的顺序完全依赖于执行计划的具体实现:
- 若使用嵌套循环连接且驱动表为
user,同用户的行可能会相邻,但这只是执行计划的副作用,并非数据库的官方承诺。 - 若使用哈希连接,结果集的顺序是随机的,大概率会出现用户行交叉的情况。
- 哪怕某次查询结果中同用户行是相邻的,当数据量变化、索引变更、PostgreSQL版本升级或配置调整时,执行计划可能改变,结果顺序也会随之变化。
解决方案
如果需要确保同一个用户的关联行一定相邻,必须显式添加ORDER BY子句,比如:
SELECT user.name, user_group.group FROM user INNER JOIN user_group ON (user.id = user_group.user_id) ORDER BY user.id;
内容的提问来源于stack exchange,提问作者Alexander Zaletilo
相关产品推荐
相关产品推荐

