表的连接方式:NESTED LOOP、HASH JOIN、SORT MERGE JOIN(修改)

表连接方式及使用场合
NESTED LOOP 嵌套循环连接   

    由两个for循环组成。不管什么连接,本算法都可以使用。连接的两个关系,分别称之为外层关系和内层关系,把数据块数大的关系作为外层关系,小的关系作内层关系。分为块嵌套循环连接(简单点说,就是把已经放在内存的两个关系块全部连接完成后再进行下一数据库块的比较,减少内存中数据块的IO)和索引嵌套循环连接(如果内层关系有索引,使用索引代替文件扫描,如果两个关系均有索引,一般把元组较少的关系作为外层关系时效果好)两种。适合于建立自然连接。
    对于被连接的数据子集较小的情况,nested loop连接是个较好的选择。nested loop就是扫描一个表,每读到一条记录,就根据索引去另一个表里面查找,没有索引一般就不会是 nested loops。
一般在nested loop中, 驱动表满足条件结果集不大,被驱动表的连接字段要有索引,这样就走nstedloop。如果驱动表返回记录太多,就不适合nested loops了。(如果连接字段没有索引,则适合走hash join,因为不需要索引。)可用ordered提示来改变CBO默认的驱动表,可用USE_NL(table_name1 table_name2)提示来强制使用nested loop。


HASH JOIN 散列连接

   可用于实现自然连接和等值连接。在散列连接算法中,散列函数h用于对两个关系的元组进行划分。此算法的基本思想是把这两个关系的元组按连接属性划分为一些有相同散列值的元组集合。
   hash join是CBO 做大数据集连接时的常用方式。优化器扫描小表(或数据源),利用连接键(也就是根据连接字段计算hash 值)在内存中建立hash表,然后扫描大表,每读到一条记录就来探测hash表一次,找出与hash表匹配的行。
当小表可以全部放入内存中,其成本接近全表扫描两个表的成本之和。如果表很大不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高I/O 的性能。临时段中的分区都需要换进内存做hash join。这时候成本接近于全表扫描小表+分区数*全表扫描大表的代价和。

    (对以上的过程保持疑问,可能是RDMS的问题,在《数据库系统概念》一书中,hash join算法的思想是这样的:对两个关系的连接属性分别作hash,hash函数一定要有较好的随机性和均匀性,如果关系r的一个元组和关系s的一个元组满足连接条件,那么他们在连接属性 上有相同的值。如该值经散列函数映射为i,则关系s的那个元组必在H(ri)中,而关系s的那个元组必在H(si)中。因此,H(ri)中的元组只需与H(si)中的元组作比较,而没有必要与s的其他任何分区作比较。很明显这种算法比以上算法代价小的多。)
    至于两个表都进行分区,其好处是可以使用parallel query,就是多个进程同时对不同的分区进行join,然后再合并。但是复杂。
使用hash join时,HASH_AREA_SIZE初始化参数必须足够的大,如果是9i,Oracle建议使用SQL工作区自动管理,设置WORKAREA_SIZE_POLICY 为AUTO,然后调整PGA_AGGREGATE_TARGET即可。
以下条件下hash join可能有优势:
两个巨大的表之间的连接。
在一个巨大的表和一个小表之间的连接。
可用ordered提示来改变CBO默认的驱动表,可用USE_HASH(table_name1 table_name2)提示来强制使用hash join。


SORT-MERGE JOIN 排序归并连接     可用于建立自然连接和等值连接。在已经排好序的两个关系上,其中重复的属性已通过投影去除。归并连接排序算法为每个关系分配一个指针,这些指针一开始指向相应关系的第一个元组,随着算法的进行,指针遍历整个关系。这样对两个关系各遍历一次。
    sort merge join的操作通常分三步:对连接的每个表做table access full;对table access full的结果进行排序;进行merge join对排序结果进行合并。sort merge join性能开销几乎都在前两步。一般是在没有索引的情况下,9i开始已经很少出现了,因为其排序成本高,大多为hash join替代了。
通常情况下hash join的效果都比sort merge join要好,然而如果行源已经被排过序,在执行sort merge join时不需要再排序了,这时sort merge join的性能会优于hash join。
在全表扫描比索引范围扫描再通过rowid进行表访问更可取的情况下,sort merge join会比nested loops性能更佳。
可用USE_MERGE(table_name1 table_name2)提示强制使用sort merge join。

一.NESTED LOOP:

1.对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择

2.使用USE_NL(table_name1 table_name2)可是强制CBO执行嵌套循环连接

3.Nested loop一般用在连接的表中有索引,并且索引选择性较好的时候

4.JOIN的顺序很重要,驱动表的记录集一定要小,返回结果集的响应时间是最快的。

5.Nested loops 工作方式是从一张表中读取数据,访问另一张表(通常是索引)来做匹配,nested loops适用的场合是当一个关联表比较小的时候,效率会更高。

例: select/*+ use_nl( test1, test2) */* from test1, test2 where test1.object_

id = test2.object_id and rownum < 2;

 

二.HASH JOIN :

1.散列连接是CBO做大数据集连接时的常用方式.

2.也可以用USE_HASH(table_name1 table_name2)提示来强制使用散列连接

3.Hash join在两个表的数据量差别很大的时候.

4.Hash join的工作方式是将一个表(通常是小一点的那个表)做hash运算,将列数据存储到hash列表中,从另一个表中抽取记录,做hash运算,到hash列表中找到相应的值,做匹配。

三.SORT MERGE JOIN

1.使用USE_MERGE(table_name1 table_name2)来强制使用排序合并连接.

2.Sort Merge join 用在没有索引,并且数据已经排序的情况.

3.

步骤:将两个表排序,然后将两个表合并。通常情况下,只有在以下情况发生时,才会使用此种JOIN方式:

1.RBO模式

2.不等价关联(>,<,>=,<=,<>)

3.HASH_JOIN_ENABLED=false

4.数据源已排序

5.Merge Join 是先将关联表的关联列各自做排序,然后从各自的排序表中抽取数据,到另一个排序表中做匹配,因为merge join需要做更多的排序,所以消耗的资源更多。通常来讲,能够使用merge join的地方,hash join都可以发挥更好的性能

类别

NESTED LOOP

SORT MERGE JOIN

HASH JOIN

优化器提示

USE_NL

USE_MERGE

USE_HASH

使用的条件

任何连接

主要用于不等价连接,如< <= > >=;

但是不包括 <>

仅用于等价连接

相关资源

CPU、磁盘I/O

内存、临时空间

内存、临时空间

特点

当有高选择性索引或进行限制性搜索时效率比较高,能够快速返回第一次的搜索结果。

当缺乏索引或者索引条件模糊时,排序合并连接比嵌套循环有效。

当缺乏索引或者索引条件模糊时,哈希连接连接比嵌套循环有效。通常比排序合并连接快。

在数据仓库环境下,如果表的纪录数多,效率高。

缺点

当索引丢失或者查询条件限制不够时,效率很低;

当表的纪录数多时,效率低。

所有的表都需要排序。它为最优化的吞吐量而设计,并且在结果没有全部找到前不返回数据。

为建立哈希表,需要大量内存。第一次的结果返回较慢。


 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
例子1:使用 nested loop 进行自然连接 ``` SELECT * FROM orders, customers WHERE orders.customer_id = customers.customer_id; ``` 执行计划: ``` -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 150K| 23M| | 2276 (1)| 00:00:01 | |* 1 | HASH JOIN | | 150K| 23M| 13M| 2276 (1)| 00:00:01 | | 2 | TABLE ACCESS FULL | CUSTOMER | 150K| 5859K| | 32 (0)| 00:00:01 | | 3 | TABLE ACCESS FULL | ORDERS | 150K| 10M| | 1206 (1)| 00:00:01 | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("ORDERS"."CUSTOMER_ID"="CUSTOMER"."CUSTOMER_ID") ``` 例子2:使用 hash join 进行自然连接 ``` SELECT /*+ USE_HASH(customers orders) */ * FROM orders, customers WHERE orders.customer_id = customers.customer_id; ``` 执行计划: ``` -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 150K| 23M| | 2461 (1)| 00:00:01 | | 1 | HASH JOIN | | 150K| 23M| 13M| 2461 (1)| 00:00:01 | | 2 | TABLE ACCESS FULL| ORDERS | 150K| 10M| | 1206 (1)| 00:00:01 | | 3 | TABLE ACCESS FULL| CUSTOMER | 150K| 5859K| | 32 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- ``` 例子3:使用 sort merge 进行自然连接 ``` SELECT /*+ USE_MERGE(customers orders) */ * FROM orders, customers WHERE orders.customer_id = customers.customer_id; ``` 执行计划: ``` --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 150K| 23M| | 3826 (1)| 00:00:01 | | 1 | MERGE JOIN | | 150K| 23M| | 3826 (1)| 00:00:01 | | 2 | SORT JOIN | | 150K| 2929K| 2912K| 759 (1)| 00:00:01 | | 3 | TABLE ACCESS | CUSTOMER | 150K| 2929K| | 32 (0)| 00:00:01 | | 4 | SORT JOIN | | 150K| 10M| 8496K| 3066 (1)| 00:00:01 | | 5 | TABLE ACCESS | ORDERS | 150K| 10M| | 1206 (1)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("ORDERS"."CUSTOMER_ID"="CUSTOMER"."CUSTOMER_ID") ``` 注意,以上的执行计划仅供参考,实际的执行计划可能会因为系统配置、数据量等因素而有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值