日期:2014-05-16  浏览次数:20397 次

SEMI-JOIN执行计划突然变成HASH JOIN了 的原因分析
甲说:
A B两个表总数据量都很大,在百万以上。
idx1  idx2字段表示是索引字段
A B 两表上都有
col1字段表示普通字段

select xxx from A
where A.idx1 between mmm and nnn
     and exists (select 1 from B where B.idx2 = A.col1)

满足A.idx1 between mmm and nnn条件的行一般是几百到几千行,选择性还可以。B表上idx2字段选择性很高。

以前执行计划是 NESTED LOOP-SEMI-JOIN,效率很高。
今天数据库负载突增,最后发现是该语句的执行计划变成 HASH JOIN-SEMI-JOIN,也就意味着对B表进行table access full!

无奈之下,修改查询语句为
... and exists (select  /*+ NL_SJ */ 1 from B where...

哪位能指点一下为什么执行计划会变得极差?



乙说:从新分析一下表在查询看看



甲说:
这是未加提示的语句及执行计划,走了HASH JOIN SEMI。[/COLOR]
[PHP]
SQL> explain plan for
  2  select count(*)
  3    from RECORD_TEMP_A t
  4   where 1 = 1
  5     and t.datsendtime >= sysdate - 20
  6     and t.datsendtime < sysdate - 10
  7     AND EXISTS (SELECT 1
  8            FROM RECORD_TEMP_B partition(P_MAXVALUE) V
  9           WHERE V.MSGID = T.MSGID);

已解释。

SQL> select * from table(dbms_xplan.display());

------------------------------------------
| Id  | Operation                             |  Name                    | Rows  | Bytes | Cost  | Pstart| Pstop |
------------------------------------------
|   0 | SELECT STATEMENT                      |                          |     1 |    64 | 17103 |       |       |
|   1 |  SORT AGGREGATE                       |                          |     1 |    64 |       |       |       |
|*  2 |   FILTER                              |                          |       |       |       |       |       |
|*  3 |    HASH JOIN SEMI                     |                          | 15167 |   947K| 17103 |       |       |
|   4 |