将“相关值”导致的Nested Loop优化成Hash Join
2011-04-12 16:54
387 查看
原文地址:http://www.itpub.net/thread-1376537-1-2.html
“相关值”是我剽窃的一个词,与之相反的是“不相关值”,我借用来描述以下这种情况:在SQL中有两个表A和B要join,join条件是A.name=B.first_name,判定符“=”左右两边的值是“不相关”的,而substr(A.name,1,length(B.first_name))=B.first_name,判定符“=”左右两边的值是“相关”的,因为要通过“=”右边的值才能求出左边的值(相反亦然)。
由于这种“相关值”的情况,A、B表join的算法注定只能走NestedLoop了,因为每一个不同的驱动值(驱动表中的值,也就是B表中的值)将改变A表负责join的值,执行计划如下:
这里展开一下,NestedLoop这个算法复杂度是O(B*A)(B表示驱动表的记录数,A表示内部表),如果A、B都很大,那就杯具了,关于NestedLoop驱动表的选取就不展开了。
网友anlinew提供了一种非常精妙的,决的优化方法,将语句改写成:
执行计划虽然变复杂了,但是耗时大幅减少,consistentgets也大幅降低,作出巨大贡献的是HashJoin的引入。
这里再展开一下,HashJoin的复杂度是O(A+B),简单来说就是对A、B表各扫描一次,如果A、B都比较大的情况来看,无疑HashJoin要比NestedLoop优越很多。
扯远了,回到anlinew的具体方法上吧,导致HashJoin出现的关键因素是一个谓词的引入:
套用我剽窃的那个词来说,这是“不相关值”的对比!
anlinew的核心思想是将数据“分片”,该例子中分片的依据是多少位首字母(这里是4),其中“大头”由HashJoin处理,而“小头”走NestedLoop,这种“抓大放小”的做法直接就从复杂度上进行了优化。
这种“分片”的思想非常值得借鉴,将“相关值”判断转化成“不相关值”的判断也是处理问题的一种有效手法。
“相关值”是我剽窃的一个词,与之相反的是“不相关值”,我借用来描述以下这种情况:在SQL中有两个表A和B要join,join条件是A.name=B.first_name,判定符“=”左右两边的值是“不相关”的,而substr(A.name,1,length(B.first_name))=B.first_name,判定符“=”左右两边的值是“相关”的,因为要通过“=”右边的值才能求出左边的值(相反亦然)。
由于这种“相关值”的情况,A、B表join的算法注定只能走NestedLoop了,因为每一个不同的驱动值(驱动表中的值,也就是B表中的值)将改变A表负责join的值,执行计划如下:
1 | select a.*,b.object_name from TEST_OBJECTa,TEST_OBJ1b |
2 | where substr(a.object_name,1,length(b.object_name))=b.object_name; |
01 | 已选择108612行。 |
02 |
03 | 已用时间:00:00:21.54 |
04 |
05 | --------------------------------------------------------------------- |
06 | |Id|Operation|Name|Rows|Bytes|Cost| |
07 | --------------------------------------------------------------------- |
08 | |0|SELECTSTATEMENT||||| |
09 | |1|NESTEDLOOPS||||| |
10 | |2|TABLEACCESSFULL|TEST_OBJ1|||| |
11 | |*3|TABLEACCESSFULL|TEST_OBJECT|||| |
12 | --------------------------------------------------------------------- |
13 |
14 | PredicateInformation(identifiedbyoperationid): |
15 | --------------------------------------------------- |
16 |
17 | 3-filter("B"."OBJECT_NAME"=SUBSTR("A"."OBJECT_NAME",1,LENGTH("B"."OBJ |
18 | ECT_NAME"))) |
19 |
20 | 统计信息 |
21 | ---------------------------------------------------------- |
22 | 1recursivecalls |
23 | 0dbblockgets |
24 | 9262734consistentgets |
网友
1 | select a.*,b.object_name from TEST_OBJECTa,TEST_OBJ1b |
2 | where substr(a.object_name,1,length(b.object_name))=b.object_name |
3 | and substr(a.object_name,1,4)=substr(b.object_name,1,4) |
4 | and length(b.object_name)>3 |
5 | union all |
6 | select a.*,b.object_name from TEST_OBJECTa,TEST_OBJ1b |
7 | where substr(a.object_name,1,length(b.object_name))=b.object_name |
8 | and length(b.object_name)<4; |
1 |
01 | 已选择108612行。 |
02 |
03 | 已用时间:00:06:51.24 |
04 |
05 | ----------------------------------------------------------------------------------- |
06 | |Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time| |
07 | ----------------------------------------------------------------------------------- |
08 | |0|SELECTSTATEMENT||3468|365K|90997(100)|00:18:12| |
09 | |1|UNION-ALL|||||| |
10 | |*2|HASHJOIN||34|3672|176(2)|00:00:03| |
11 | |*3|TABLEACCESSFULL|TEST_OBJ1|659|12521|35(0)|00:00:01| |
12 | |4|TABLEACCESSFULL|TEST_OBJECT|52544|4566K|139(1)|00:00:02| |
13 | |5|NESTEDLOOPS||3434|362K|90821(1)|00:18:10| |
14 | |*6|TABLEACCESSFULL|TEST_OBJ1|659|12521|35(0)|00:00:01| |
15 | |*7|TABLEACCESSFULL|TEST_OBJECT|5|445|138(1)|00:00:02| |
16 | ----------------------------------------------------------------------------------- |
17 |
18 | PredicateInformation(identifiedbyoperationid): |
19 | --------------------------------------------------- |
20 |
21 | 2-access(SUBSTR("A"."OBJECT_NAME",1,4)=SUBSTR("B"."OBJECT_NAME",1,4)) |
22 | filter("B"."OBJECT_NAME"=SUBSTR("A"."OBJECT_NAME",1,LENGTH("B"."OBJE |
23 | CT_NAME"))) |
24 | 3-filter(LENGTH("B"."OBJECT_NAME")>3) |
25 | 6-filter(LENGTH("B"."OBJECT_NAME")<4) |
26 | 7-filter("B"."OBJECT_NAME"=SUBSTR("A"."OBJECT_NAME",1,LENGTH("B"."OBJE |
27 | CT_NAME"))) |
28 |
29 | 统计信息 |
30 | ---------------------------------------------------------- |
31 | 1recursivecalls |
32 | 0dbblockgets |
33 | 33946consistentgets |
这里再展开一下,HashJoin的复杂度是O(A+B),简单来说就是对A、B表各扫描一次,如果A、B都比较大的情况来看,无疑HashJoin要比NestedLoop优越很多。
扯远了,回到
1 | and substr(a.object_name,1,4)=substr(b.object_name,1,4) |
这种“分片”的思想非常值得借鉴,将“相关值”判断转化成“不相关值”的判断也是处理问题的一种有效手法。
相关文章推荐
- SQL优化:Merge Join vs. Hash Join vs. Nested Loop
- oracle hash join和nested loop下的驱动表相关测试
- SQL优化(一)Merge Join vs. Hash Join vs. Nested Loop
- Sql优化(一) Merge Join vs. Hash Join vs. Nested Loop
- Oracle优化器、优化模式、表的连接方式(Hash Join、Nested Loop、Sort Merge Join)
- Sql优化(一) Merge Join vs. Hash Join vs. Nested Loop
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- Merge join、Hash join、Nested loop join对比分析
- SQL优化(一) Merge Join VS. Hash Join VS. Nested Loop
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 表的连接方式:NESTED LOOP、HASH JOIN、SORT MERGE JOIN
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP .
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 【MySQL】MySQL性能优化之Block Nested-Loop Join(BNL)
- 表的连接方式:NESTED LOOP、HASH JOIN、MERGE JOIN(修改)
- 5年前面试题引发的“血案”(4)(nested loop和hash join,索引和约束的小技巧)
- 浅谈SQL中的三种物理连接操作(HASH JOIN MERGE JOIN NESTED LOOP)
- HASH JOIN ,MERGE JOIN ,NESTED LOOP 比较
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP