postgresql:诡异的left join结果

在修改数据中心后台系统的代码时候,遇到了一个诡异的sql问题,在此记录一下,我还没有找到原因。
fund与mdfund表之间是M:N关系(多对多),其中mdfund记录的是多对多的关系。

系统中需要找出所有符合一定条件的fund记录,以及其与metadata的关系(记录在mdfund表),因此想当然的用是这个SQL代码:

select distinct f.*,mf.id as mfid,mf.fid,mf.place from fund f
left join mdfund mf on f.id=mf.fid
where mf.uuid='b7beb8bf-58d9-4e58-a945-7b6e1dc7705f' and (f.title like '%9112%' or f.fund_id like '%9112%')

这个代码运行出来的结果只有一行记录,将mdfund中有记录的数据给查询出来了,但mdfund中没有记录的数据就没有查询出来,这不是我想要的结果。
尝试换用right join、outer join等,都不是我想要的结果。

因此,决定用个笨点的方法尝试一下,
select * from
(
select distinct f.* from fund f where (f.title like '%9112%' or f.fund_id like '%9112%')
) a
left join
(
select mf.id as mfid,mf.fid,mf.place from mdfund mf where mf.uuid='b7beb8bf-58d9-4e58-a945-7b6e1dc7705f'
) b
on a.id=b.fid

这次出来的结果就是正确的,因此将sql代码优化一下:

select distinct f.*,mf.id as mfid,mf.fid,mf.place from fund f
left join
(
select * from mdfund mf where uuid='b7beb8bf-58d9-4e58-a945-7b6e1dc7705f'
) mf
on f.id=mf.fid
where (f.title like '%9112%' or f.fund_id like '%9112%')

这样的结果是正确的,和第一次尝试的区别就是将uuid限制条件前移了。

这个诡异的差别,为啥能解决问题,我还没有想清楚。

二者的sql解释,正确sql的执行
"HashAggregate (cost=16.97..17.23 rows=26 width=245)"
" -> Hash Right Join (cost=10.08..16.25 rows=26 width=245)"
" Hash Cond: (mf.fid = f.id)"
" -> Bitmap Heap Scan on mdfund mf (cost=4.27..10.42 rows=3 width=12)"
" Recheck Cond: (uuid = 'b7beb8bf-58d9-4e58-a945-7b6e1dc7705f'::uuid)"
" -> Bitmap Index Scan on mdfund_uuid_fid_key (cost=0.00..4.27 rows=3 width=0)"
" Index Cond: (uuid = 'b7beb8bf-58d9-4e58-a945-7b6e1dc7705f'::uuid)"
" -> Hash (cost=5.48..5.48 rows=26 width=233)"
" -> Seq Scan on fund f (cost=0.00..5.48 rows=26 width=233)"
" Filter: ((title ~~ '%9112%'::text) OR ((fund_id)::text ~~ '%9112%'::text))"

错误结果的sql执行:
"HashAggregate (cost=16.28..16.29 rows=1 width=245)"
" -> Hash Join (cost=10.08..16.25 rows=1 width=245)"
" Hash Cond: (mf.fid = f.id)"
" -> Bitmap Heap Scan on mdfund mf (cost=4.27..10.42 rows=3 width=12)"
" Recheck Cond: (uuid = 'b7beb8bf-58d9-4e58-a945-7b6e1dc7705f'::uuid)"
" -> Bitmap Index Scan on mdfund_uuid_fid_key (cost=0.00..4.27 rows=3 width=0)"
" Index Cond: (uuid = 'b7beb8bf-58d9-4e58-a945-7b6e1dc7705f'::uuid)"
" -> Hash (cost=5.48..5.48 rows=26 width=233)"
" -> Seq Scan on fund f (cost=0.00..5.48 rows=26 width=233)"
" Filter: ((title ~~ '%9112%'::text) OR ((fund_id)::text ~~ '%9112%'::text))"

可以看出,唯一的区别就是第二行,正确结果做了一次right join,而错误结果中没有执行right join。
而在sql中直接指定right join同样也不解决问题。


已发布

分类

,

来自

标签:

评论

《“postgresql:诡异的left join结果”》 有 1 条评论

  1. wangliangxu 的头像

    这个问题,或许应该 @PostgreSQL中文社区 ,不知道能否指教

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注