PgSQL外连接分页时出现重复数据
今天工作中遇到的问题。
SELECT * FROM a LEFT JOIN b
ON a.c = b.d
LIMIT 20 OFFSET 0;
SELECT * FROM a LEFT JOIN b
ON a.c = b.d
LIMIT 20 OFFSET 20;
上面两条是一摸一样的语句,只有OFFSET参数不同,相当于第一条语句显示出第一页的数据,第二条显示出第二页,页大小为20,不同的两页理应不应该有重复数据,但确实出现了。
但当我把公司的两张表弄到我的pgsql上,问题就没了
公司PGSQL版本:12.2
我的PGSQL版本:14.5
最开始怀疑的方向错了,看到版本不同表现不同,就怀疑是优化器的锅了。
果然,offset为0和offset为20时所使用的执行计划不同,offset为0时被转成了Right Join,而高版本就没这个问题。
按理来说,Right Join和Left Join也不应该造成结果有差异,因为都是双层循环,主表(在这个例子中是a)在外层循环中。但关键是这个用的又是什么Hash Join。我之前没了解过(好像数据库系统里学过),不过应该是Hash Join使得左右连接产生了不同的结果。
解决办法
- 添加Order by确定排序顺序
- 关闭hashjoin
- 不知道PgSQL有没有索引提示这种东西,如果有的话可以影响执行计划的选择