oracle 连接的使用,Oracle 连接和半连接

连接

ORACLE多表连接分为三大类:NEXT LOOP、SORT MERGE、HASH JOIN。

每一类又分为三小类,有传统连接,Semi Join, Anti Join。(后两种叫做半连接)

NEST LOOP方式:

有两个表,驱动表Driving Table,被驱动表Driven Table。

驱动表做一次遍历,被驱动表做多次遍历。

返回第一条记录速度很快,不需要排序。

可以使用非等值连接。

SORT MERGE方式:

两个表地位一样。每个表都要先排序,然后进行合并,返回记录集。

排序首先在内存中进行,能在内存中完成的叫做Optimal Sort,也叫In-Memory

Sort。如果需要借助磁盘缓冲,叫做外部排序External Sort。

在外部排序中,运行run是指一次对磁盘做IO。

如果一次输入就能完成整个数据集的排序叫做1路排序1-Pass Sort。需要多次输入输出操作的叫多路排序Multi-Pass

Sort。

从性能角度来看Optimal Sort>1-Pass

Sort>Multi-Pass Sort

执行计划中

OMem:代表使用Optimal排序需要的内存估量。

1Mem:代表使用1-Pass排序需要的内存估量。

O/1/M:代表实际Optimal、1-Pass、Multi-Pass方式的执行次数。

HASH JOIN方式:

一个驱动表,一个被驱动表。过程有两个阶段:

准备阶段:对驱动表的连接字段进行哈希操作,产生一系列的Hash Bucket(哈希桶)

探测阶段:依次上去被驱动表每条记录,对连接字段执行相同哈希函数,和驱动表哈希桶进行匹配,这个过程叫探测(Probe)。

几种方式比较:

ORACLE实现排序都是用二叉树插入排序算法(Binary Insertion Tree)。

内存中的INDEX中,每个节点对应一条记录,每个节点还保存一个父节点和两个子节点的指针。这样在32位系统中,这个开销是12字节,64位系统中,这个开销是24字节。

排序过程是内存和CPU的双重密集操作。

完全内存排序有时候不必磁盘排序快。

如果CPU是资源瓶颈,IO比较空闲,应该减少排序空间大小,使用1-Pass

Sort。尤其是在创建索引时,通过减少SORT_AREA_SIZE来提升性能。因为内存排序和磁盘排序,记录比较操作相差不大,但是内存排序中,二叉树可能过高,CPU资源消耗太大。

HASH JOIN内存消耗远小于SORT MERGE,也不需要密集的CPU操作。所以HASH JOIN算法普遍优于SORT

MERGE算法。

如果查询关注的是整个记录而不畅部分记录时,HASH JOIN非常类似NEST LOOP,但优于NEST LOOP,因为HASH

TABLE构建在PGA中,不需要LATCH保护。

半连接

是针对IN, EXISTS, NOT IN, NOT EXISTS的变形。

子查询在FROM里的叫做IN-LINE VIEW,在WHERE子句中的叫NESTED SUBQUERY(嵌套子查询)。IN,

EXISTS, NOT IN, NOT EXISTS都属于嵌套子查询。

对于嵌套子查询,ORACLE处理有两种方式:展开子查询,不展开子查询。

对于嵌套视图,ORACLE处理方法有两种,合并,不合并。

ORACLE 10G以前的优化器会在Optimization之前就展开,不做成本评估。

In、Exists展开结果是变成Semi-Join。Not Exists和Not In是转换成Anti-Join。

对于Inline-View或者其它View,Oracle也会尝试合并到主查询中,这个动作叫做Merge,对应hint是和。这个在执行计划中进行确认就可以。也就是,如果没有VIEW字样,就是发生了MERGE合并;有VIEW字样,就是没有做MERGE合并。

对于子查询展开,这个过程叫做Subquery Unnesting。

Merge和Unnest不同的地方是,对于Distinct、Group by这些子句,Merge可以合并,叫做Complex

View Merge,Set和Unnest一样,不能合并。

缺省时,不进行Complex View Merge。使用才能达到Merge效果。

子查询合并到主查询中,好处是优化器可以通判考虑访问路径方式。否则,ORACLE只能针对外层内存查询分别优化。而且可以利用ORACLE提供的Semi-Join、Anti-Join两种连接方式。

不是所有子查询都可以展开,例如,connect by, start with, rownum伪列,

set操作符(UNION、UNION ALL、MINUS、INTERSECT)、聚集函数(SUM、COUNT、GROUP

BY)不会被展开。

半连接关注重点在于:对于外表某个记录,在内表中找到一个匹配记录就返回外表记录。

不展开查询:

类似NEST LOOP方式,对主查询每条记录都执行一次子查询,在执行计划中叫做FILTER。

ORACLE 10G中,使用提示。(这个是非半连接)

SQL>SELECT ID

FROM A

WHERE EXISTS ( SELECT 1 FROM B WHERE A.ID=B.P_ID);

展开子查询:

SQL>SELECT ID

FROM A

WHERE EXISTS ( SELECT 1 FROM B WHERE A.ID=B.P_ID);

此时执行计划中,会看到HASH JOIN SEMI字样,说明这是一个半连接。

好处是:

对于A表中一条记录,发现B中匹配一条就停止扫描B,转而处理A的下一条记录。

返回结果无需去重,即使A和B记录时1:n,表A每个记录只会返回一次。

从ORACLE 9i开始IN和EXISTS已经没有区别了,执行计划是一样的。

SEMI JOIN的HINT如下:

EXISTS:

SQL>SELECT ID

FROM A

WHERE EXISTS (SELECT 1 FROM B WHERE A.ID=B.P_ID);

IN:

SQL>SELECT ID

FROM A

WHERE IN (SELECT 1 FROM B WHERE A.ID=B.P_ID);

NOT EXISTS:默认就使用展开的ANTI-JOIN

SQL>SELECT ID

FROM A

WHERE NOT EXISTS (SELECT 1 FROM B WHERE A.ID=B.P_ID);

NOT IN:

与NOT EXISTS的区别在于处理NULL

NOT IN查看子结果中有没有NULL,如果有NULL,返回FALSE;NOT

EXISTS不关心有没有NULL,只关心记录数,如果有记录,返回FALSE。

NOT IN可能在匹配列上,引起性能问题,原因是索引失效。

HINT:

操作

Nest Loop

Hash Join

Sort Mereg

Join

USE_NL

USE_HASH

USE_MERGE

Anti Join

NL_AJ

HASH_AJ

MERGE_AJ

Semi

NL_SJ

HASH_SJ

MERGE_SJ

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值