Oracle Hint no_merge(merge)、no_unnest(unnest)的作用对象陷阱
Oracle Hint no_merge(merge)、no_unnest(unnest)的作用对象陷阱
Oracle的查询转换中有两个概念,子查询展开和视图合并。
关于两者的概念这里不赘述,可以看看崔华的《基于Oracle的SQL优化》这本书。
其中,no_unnest(unnest)这个Hint显式控制是否对子查询做展开,no_unnest表示该子查询不展开,unnest表示子查询展开。
而no_merge(merge)这个Hint显式控制是否进行视图合并,no_merge表示视图不合并,merge表示试图合并。
实际上最近又遇到对子查询使用no_unnest不生效的情况了,然后使用no_merge生效的情况。
还楞了好一会才反应过来,所以决定还是记录下。
崔华的《基于Oracle的SQL优化》的P642页介绍了merge和no_merge的使用对象和作用,
MERGE是针对单个目标视图的Hint,它的含义是让优化器对目标视图执行视图合并(View Merging)。
而P643页介绍了unnest和no_unnest的使用对象和作用,
UNNEST是针对子查询的Hint,它的含义是让优化器对目标SQL中的子查询执行子查询展开(Subquery Unnesting)。
举个例子,select * from a left join (select * from m where m.id=100) b on a.id=b.id。
这条sql使用no_unnest是不生效的,比如这就是有问题的:select * from a left join (select /*+ no_unnest */ * from m where m.id=100) b on a.id=b.id。
只能使用no_merge。
搞清楚这个问题只需要理解子查询的概念:当一个查询是另一个查询的条件时,称之为子查询。
一直潜意识就认为子查询就是嵌套的另外一些SELECT查询,实际上还要满足是另外一个查询的条件。
像上边的例子,显然不满足第二点。
而且实际上可以拿一个视图名字替换掉查询块内容而不会产生语法错误,比如变成select * from a left join view_name b on a.id=b.id那么这里就起到的是”视图“的作用,因此用no_merge。
像select * from a where a.id in (select b.id from b)则无法替换掉,否则产生语法错误。比如select * from a where a.id in view_name那就有问题了。
最后引用崔华的《基于Oracle的SQL优化》P337的一段话:
Oracle数据库里子查询前的where条件如果是如下这些条件之一,那么这种类型的目标SQL在满足了一定的条件后就可以做子查询展开:
- SINGLE-ROW(即=、<、>、<=、>=和<>)
- EXISTS
- NOT EXISTS
- IN
- NOT IN
- ANY
- ALL
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?