`

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 |     TABLE ACCESS BY GLOBAL INDEX ROWID| RECORD_TEMP_A            | 22142 |   648K| 10881 | ROWID | ROW L |
|*  5 |      INDEX RANGE SCAN                 | IDX_REC_TEMP_A_SENDTIME  | 39856 |       |   464 |       |       |
|*  6 |     TABLE ACCESS FULL                 | RECORD_TEMP_B            |   682K|    22M|  5779 |    24 |    24 |
------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
省略...

Note: cpu costing is off

已选择22行。
[/PHP]


这是加了NL_SJ提示的语句及执行计划,走了NESTED LOOPS 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 /*+ NL_SJ */ 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 | 77307 |       |       |
|   1 |  SORT AGGREGATE                       |                          |     1 |    64 |       |       |       |
|*  2 |   FILTER                              |                          |       |       |       |       |       |
|   3 |    NESTED LOOPS SEMI                  |                          | 15167 |   947K| 77307 |       |       |
|   4 |     TABLE ACCESS BY GLOBAL INDEX ROWID| RECORD_TEMP_A            | 22142 |   648K| 10881 | ROWID | ROW L |
|*  5 |      INDEX RANGE SCAN                 | IDX_REC_TEMP_A_SENDTIME  | 39856 |       |   464 |       |       |
|*  6 |     TABLE ACCESS BY GLOBAL INDEX ROWID| RECORD_TEMP_B            |   467K|    15M|     3 |    24 |    24 |
|*  7 |      INDEX RANGE SCAN                 | IDX_REC_B_MSGID          |     1 |       |     2 |       |       |
------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
省略...

Note: cpu costing is off

已选择23行。

SQL> spool off

乙说:

问题应该在这里
TABLE ACCESS BY GLOBAL INDEX ROWID| RECORD_TEMP_A            | 22142
|*  5 |      INDEX RANGE SCAN                 | IDX_REC_TEMP_A_SENDTIME  | 39856 |     

这里外表评估的cardinality是错误的,跟楼主说的“满足A.idx1 between mmm and nnn条件的行一般是几百到几千行,选择性还可以”严重不符

内表结果集2万多,外表68万,CBO选择hash join无可厚非

分享到:
评论

相关推荐

    分布式系统中Semi-Join算法的实现.pdf

    传统的Join操作算法有NestLoopJoin、MergeJoin和HashJoin等,这些算法在集中式环境下表现良好,但当被应用于分布式环境下时,由于网络延迟和数据传输的开销,它们的性能往往不如预期。 Semi-Join算法是为了解决...

    基于分布式系统OceanBase的并行连接.pdf

    OceanBase系统中执行的主要join算法包括nested loop join、hash join和semi-join。这些算法各有优劣,适用的场景和效率也有所不同。 nested loop join是一种基本的join算法,它通过遍历一个表的所有行,并对另一个...

    Mysql查询优化器.rar

    MySQL查询优化器是数据库管理系统中的核心组件,负责解析SQL语句并制定出执行查询的最佳计划。这个过程涉及多个阶段,包括解析、预处理、优化和执行。本资料“Mysql查询优化器.rar”包含了对这一关键主题的深入探讨...

    Query Optimization with MySQL 5.7 and MariaDB 10 Even newer tricks

    - **Semi-Join**: 对于某些特定类型的子查询,使用半连接(semi-join)而非传统的嵌套循环可以大大提高效率。 ##### IN-to-EXISTS 对于某些类型的子查询,将 IN 操作转换为 EXISTS 操作可以更有效地执行,特别是在...

    海量数据库解决方案_韩国_李华植

    第1部分中以影响数据读取效率的所有要素为类别,对其各自的概念、原理、 特征、应用准则,以及表的结构特征、多样化的索引类型、优化器的内部作用、优化器为各种结果制定的执行计划予以详细说明,并以对优化器的...

    海量数据库解决方案_韩国_李华植_Part02

    第1部分中以影响数据读取效率的所有要素为类别,对其各自的概念、原理、 特征、应用准则,以及表的结构特征、多样化的索引类型、优化器的内部作用、优化器为各种结果制定的执行计划予以详细说明,并以对优化器的...

    Oracle SQL 优化与调优技术详解-附录:SQL提示.pdf

    - **ANTIJOIN**、**SEMIJOIN**:控制反连接和半连接的转换。 - **COALESCE_SQ**、**NO_COALESCE_SQ**:是否合并子查询。 - **ELIMINATE_JOIN**、**NO_ELIMINATE_JOIN**:是否消除连接操作。 - **ELIMINATE_OBY**、**...

    Oracle SQL Hints

    Oracle SQL Hints是一种在Oracle数据库中用于优化SQL语句执行计划的辅助手段。通过在SQL语句中嵌入特定的指令,即HINT,可以向Oracle优化器强制指示使用特定的访问路径、关联方法等,以便绕过优化器的默认选择,从而...

    ORACLE初始化参数详解

    - **说明**:此参数控制半连接(Semi-Join)的执行方式。半连接用于返回主表中满足子查询条件的行。 - **值范围**: - `NESTED_LOOPS`:采用嵌套循环算法执行。 - `MERGE`:采用排序合并算法执行。 - `HASH`:...

    微软内部资料-SQL性能优化5

    Having useful indexes speeds up finding individual rows in a table, as well as finding the matching rows needed to join two tables. What You Will Learn After completing this lesson, you will be able ...

    ORACLE 高效SQL分析2(具体问题)

    执行计划通常为`HASH JOIN SEMI`(哈希半连接),这是一种特殊的连接类型,仅需返回满足条件的行的一部分即可。 - **优化建议**:对于只需要确定是否存在匹配项的情况,优先使用`EXISTS`而不是`IN`,尤其是在子查询...

    Oracle中的半联结和反联结详解

    在Oracle数据库中,半联结(Semi-Join)和反联结(Anti-Join)是两种特殊的联结方式,它们在处理多表查询时能提供高效的数据筛选。半联结用于找出那些在一张表中存在,而在另一张表中至少有一个匹配的记录的行,而反...

    分布式关系型数据库RadonDB介绍.pptx

    分布式SQL节点负责生成和执行分布式执行计划,可以并行执行SQL语句,同时具备分布式事务协调能力,处理如`orderby`、`limit`、`groupby`、`aggregation`和`join`等复杂的操作。这些节点设计为无中心化,确保系统的高...

    oracle初始化参数详解

    `always_semi_join`则影响EXISTS子查询的执行,当没有索引时,半连接可能会提高性能。 2. **aq_tm_processes**:此参数用于启用队列消息的时间监控,其值决定可以监视的消息数量,影响应用程序的延迟和失效特性。 ...

    mysql5.6官方最新手册

    另外,SQL查询的性能也有所提高,例如通过改进的查询优化器,能够更好地处理JOIN操作和子查询。 二、存储引擎的改进 InnoDB存储引擎在5.6版本中得到了重大优化。表空间管理更高效,支持在线DDL(Data Definition ...

    oracle数据库参数

    `always_anti_join` 控制如何处理NOT IN子查询,可以选择NESTED_LOOPS(嵌套循环)、MERGE(合并)或HASH方法。`always_semi_join`则涉及EXISTS子查询的优化,如果在限制子查询的列上有索引,使用半连接可以提高性能...

Global site tag (gtag.js) - Google Analytics