一般来说,联结方法分为:嵌套循环联结(Nested Loops),散列联结(Hash-Join),排序合并联结(Sort Merge Join)以及笛卡尔联结(Merge Join Cartesian).
1、嵌套循环联结(Nested Loops)
嵌套循环有外部表(drivingtable,驱动表)和内部表(inner或driven-to table ,被驱动表)的概念,一般来说,结果集大的成为内部表,结果集小的成为外部表。由外部表(结果集)来驱动内部表。
嵌套循环联结使用一次访问运算所得的结果集(外部表)中的每一行来与另一个表(内部表)进行对碰。如果结果集的大小是有限的并且在用来联结的列(inner table 的列)上有索引的话,这种联结的效率通常是最高的。
简而言之,这种类型的联结,如果外部表(结果集)非常小,而内部表(结果集)非常大并且已预先建立索引,那么嵌套循环联接将特别有效率。
优缺点:使用内存非常小,因为不排序,且数据行集一次只加工一行,所需的开支非常小。也正是这个原因,除了建立一个大数据集所花的时间较长这一点之外,它也是适合进行大数据集加工的。
嵌套循环联结的基本度量是为了准备最终结果集所需要访问的数据块数目。
2、排序合并联结(Sort Merge Join)
内部连接过程:
1) 首先生成 rowsource1 需要的数据,然后对这些数据按照连接操作关联列(如 A.col3 )进行排序。
2) 随后生成 rowsource2 需要的数据,然后对这些数据按照与 sort source1 对应的连接操作关联列(如 B.col4 )进行排序。
3) 最后两边已排序的行被放在一起执行合并操作,即将 2 个 row source 按照连接条件连接起来
下面是连接步骤的图形表示:
MERGE
/ /
SORT SORT
| |
Row Source1 Row Source 2
如果 row source已经在连接关联列上被排序,则该连接操作就不需要再进行 sort 操作,这样可以大大提高这种连接操作的连接速度,因为排序是个极其费资源的操作,特别是对于较大的表。预先排序的 row source 包括已经被索引的列(如 a.col3 或 b.col4 上有索引)或 row source 已经在前面的步骤中被排序了。尽管合并两个 row source 的过程是串行的,但是可以并行访问这两个 row source (如并行读入数据,并行排序)。一旦数据集排序完成了,合并过程是非常快的。
排序合并联结一般最适合于数据筛选条件有限并返回有限数据行的查询。若关联列没有可用的索引时,排序合并联结也通常是较好的选择。
总的来说,在条件为非等值式的时候,排序合并联结通常是最好的选择。列如:where table1.col1 between table2.col1 and table2.col2 ,这样的连接条件就较适合排序合并联结。(这种情况散列联结是不可能的)
如果数据行源非常大,排序合并联结就可能是唯一可行的选择。
3、散列联结(Hash-Join,哈希联结)
这种联结是在 oracle7.3 以后引入的,从理论上来说比 NL(嵌套循环) 与 SMJ(排序合并) 更高效,而且只用在 CBO 优化器中。
首先应用where条件的筛选标准来读取要进行联结的两个表,基于表和索引的统计信息,确定小的结果集并完全散列化到内存中。这个散列表包含了源结果集的所有数据行,并被联结键转化为散列值的随机函数载入到散列桶中。只要内存充足,这个散列表一直保存在内存中,若内存不足,则写到磁盘。
然后就是读取大结果集并对联结键列应用散列函数。
较小的 rowsource 被用来构建 hash table 与 bitmap ,第 2 个 row source 被用来被 hansed ,并与第一个 row source 生成的 hash table 进行匹配,以便进行进一步的连接。 Bitmap 被用来作为一种比较快的查找方法,来检查在 hash table 中是否有匹配的行。特别的,当 hash table 比较大而不能全部容纳在内存中时,这种查找方法更为有用。这种连接方法也有 NL连接中所谓的驱动表的概念,被构建为 hash table 与 bitmap 的表为驱动表,当被构建的 hash
table 与 bitmap 能被容纳在内存中时,这种联结方式的效率极高。
要使哈希连接有效,需要设置 HASH_JOIN_ENABLED=TRUE ,缺省情况下该参数为 TRUE ,另外,不要忘了还要设置 hash_area_size 参数,以使哈希连接高效运行,因为哈希连接会在该参数指定大小的内存中运行,过小的参数会使哈希连接的性能比其他连接方式还 要低。
注意:决定哪个表是最小的不仅取决于数据行数,还取决于这些行的大小,因为整个行都会存放在散列表中。
最后,总结一下,在哪种情况下用哪种连接方法比较好:
排序 合并联结( SortMerge Join , SMJ ):
a ) 对于非等值连接,这种连接方式的效率是比较高的。
b ) 如果在关联的列上都有索引,效果更好。
c ) 对于将 2 个较大的 rowsource 做连接,该连接方法比 NL 连接要好一些。
d ) 但是如果 sortmerge 返回的 row source 过大,则又会导致使用过多的 rowid 在表中查询数据时,数据库性能下降,因为过多的 I/O.
嵌套循环( NestedLoops , NL ):
a ) 如果 drivingrow source (外部表)比较小,并且在 inner row source (内部表)上有唯一索引,或有高选择性非唯一索引时,使用这种方法可以得到较好的效率。
b ) NESTEDLOOPS 有其它连接方法没有的的一个优点是:可以先返回已经连接的行,而不必等待所有的连接操作处理完才返回数据,这可以实现快速的响应时间。
哈希联结( HashJoin , HJ ):
a ) 这种方法是在 oracle7 后来引入的,使用了比较先进的连接理论,一般来说,其效率应该好于其它 2 种连接,但是这种连接只能用在 CBO 优化器中,而且需要设置合适的 hash_area_size 参数,才能取得较好的性能。
b ) 在 2 个较大的 rowsource 之间连接时会取得相对较好的效率,在一个 row source 较小时则能取得更好的效率。
c ) 只能用于等值连接中
d )对索引不要求(有索引也可能走索引,它不会限制sql是访问方式)