SQL 语句优化 --将Exists转换成 inner join 语句来选择正确的执行计划
这段时间优化时,发现一个语句执行时间很长,效率很低,语句如下:
select id,field015,field016,field017,field001,field020,field010,field014,field011,field013,field004,field018,
field005,field007,field003,null ,requestid from ufv3a7n71178865841875 tbalias where requestid in( select id from workflowbase wb where wb.isdelete<>1 and isfinished=0 ) and
exists (select 'X' from Permissiondetail p where p.objid=tbalias.requestid and p.objtable='workflowbase' and ((p.userid='40282c48177be3a001177fefe73843d8') or (( p.isalluser=1 or p.orgid='40288a7d0f55fb5a010f569c2bf01205')
and (p.minseclevel <= 10 and ((( p.maxseclevel is not null) and (10<= p.maxseclevel)) or (p.maxseclevel is null))))))
order by field017 desc,id desc
field005,field007,field003,null ,requestid from ufv3a7n71178865841875 tbalias where requestid in( select id from workflowbase wb where wb.isdelete<>1 and isfinished=0 ) and
exists (select 'X' from Permissiondetail p where p.objid=tbalias.requestid and p.objtable='workflowbase' and ((p.userid='40282c48177be3a001177fefe73843d8') or (( p.isalluser=1 or p.orgid='40288a7d0f55fb5a010f569c2bf01205')
and (p.minseclevel <= 10 and ((( p.maxseclevel is not null) and (10<= p.maxseclevel)) or (p.maxseclevel is null))))))
order by field017 desc,id desc
执行计划:
执行结果:
(1578 行受影响)
表 'workflowbase'。扫描计数 0,逻辑读取 34932 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'permissiondetail'。扫描计数 8145,逻辑读取 48196 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'ufv3a7n71178865841875'。扫描计数 1,逻辑读取 576 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'workflowbase'。扫描计数 0,逻辑读取 34932 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'permissiondetail'。扫描计数 8145,逻辑读取 48196 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'ufv3a7n71178865841875'。扫描计数 1,逻辑读取 576 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
将 exists语句转换成inner join 语句,改成后的语句如下:
select distinct tbalias.id,field015,field016,field017,field001,field020,field010,field014,field011,field013,field004,field018,
field005,field007,field003,null ,requestid from ufv3a7n71178865841875 tbalias
inner join workflowbase wb on wb.id=tbalias.requestid and wb.isdelete<>1 and isfinished=0
inner join Permissiondetail p on p.objid=tbalias.requestid and p.objtable='workflowbase' and
((p.userid='40282c48177be3a001177fefe73843d8') or (( p.isalluser=1 or p.orgid='40288a7d0f55fb5a010f569c2bf01205')
and (p.minseclevel <= 10 and ((( p.maxseclevel is not null) and (10<= p.maxseclevel)) or (p.maxseclevel is null)))))
order by field017 desc,id desc
field005,field007,field003,null ,requestid from ufv3a7n71178865841875 tbalias
inner join workflowbase wb on wb.id=tbalias.requestid and wb.isdelete<>1 and isfinished=0
inner join Permissiondetail p on p.objid=tbalias.requestid and p.objtable='workflowbase' and
((p.userid='40282c48177be3a001177fefe73843d8') or (( p.isalluser=1 or p.orgid='40288a7d0f55fb5a010f569c2bf01205')
and (p.minseclevel <= 10 and ((( p.maxseclevel is not null) and (10<= p.maxseclevel)) or (p.maxseclevel is null)))))
order by field017 desc,id desc
执行计划:
执行结果:
(1578 行受影响)
表 'permissiondetail'。扫描计数 2988,逻辑读取 17298 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'ufv3a7n71178865841875'。扫描计数 1,逻辑读取 576 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'workflowbase'。扫描计数 1,逻辑读取 1425 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'permissiondetail'。扫描计数 2988,逻辑读取 17298 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'ufv3a7n71178865841875'。扫描计数 1,逻辑读取 576 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'workflowbase'。扫描计数 1,逻辑读取 1425 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
通过使用 inner join 替换 exists ,我们发现执行计划里将 哈希联结(Hash join)换成了 嵌套循环(Nested Loops) ,IO次数明细减少。
总结:
以前写过一优化文章" SQL优化--使用 EXISTS 代替 IN 和 关联查询(inner join) ",提示用exists替换inner join ,这个替换是有前提条件,要经过测试的,今天我们又使用 inner join 替换 exists ,也是在实际情况中的使用,两者没有具体的公式。
目的:是在特定情况下让优化器能使用正确的执行计划。