甲说:
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无可厚非
分享到:
相关推荐
传统的Join操作算法有NestLoopJoin、MergeJoin和HashJoin等,这些算法在集中式环境下表现良好,但当被应用于分布式环境下时,由于网络延迟和数据传输的开销,它们的性能往往不如预期。 Semi-Join算法是为了解决...
OceanBase系统中执行的主要join算法包括nested loop join、hash join和semi-join。这些算法各有优劣,适用的场景和效率也有所不同。 nested loop join是一种基本的join算法,它通过遍历一个表的所有行,并对另一个...
MySQL查询优化器是数据库管理系统中的核心组件,负责解析SQL语句并制定出执行查询的最佳计划。这个过程涉及多个阶段,包括解析、预处理、优化和执行。本资料“Mysql查询优化器.rar”包含了对这一关键主题的深入探讨...
- **Semi-Join**: 对于某些特定类型的子查询,使用半连接(semi-join)而非传统的嵌套循环可以大大提高效率。 ##### IN-to-EXISTS 对于某些类型的子查询,将 IN 操作转换为 EXISTS 操作可以更有效地执行,特别是在...
第1部分中以影响数据读取效率的所有要素为类别,对其各自的概念、原理、 特征、应用准则,以及表的结构特征、多样化的索引类型、优化器的内部作用、优化器为各种结果制定的执行计划予以详细说明,并以对优化器的...
第1部分中以影响数据读取效率的所有要素为类别,对其各自的概念、原理、 特征、应用准则,以及表的结构特征、多样化的索引类型、优化器的内部作用、优化器为各种结果制定的执行计划予以详细说明,并以对优化器的...
- **ANTIJOIN**、**SEMIJOIN**:控制反连接和半连接的转换。 - **COALESCE_SQ**、**NO_COALESCE_SQ**:是否合并子查询。 - **ELIMINATE_JOIN**、**NO_ELIMINATE_JOIN**:是否消除连接操作。 - **ELIMINATE_OBY**、**...
Oracle SQL Hints是一种在Oracle数据库中用于优化SQL语句执行计划的辅助手段。通过在SQL语句中嵌入特定的指令,即HINT,可以向Oracle优化器强制指示使用特定的访问路径、关联方法等,以便绕过优化器的默认选择,从而...
- **说明**:此参数控制半连接(Semi-Join)的执行方式。半连接用于返回主表中满足子查询条件的行。 - **值范围**: - `NESTED_LOOPS`:采用嵌套循环算法执行。 - `MERGE`:采用排序合并算法执行。 - `HASH`:...
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 ...
执行计划通常为`HASH JOIN SEMI`(哈希半连接),这是一种特殊的连接类型,仅需返回满足条件的行的一部分即可。 - **优化建议**:对于只需要确定是否存在匹配项的情况,优先使用`EXISTS`而不是`IN`,尤其是在子查询...
在Oracle数据库中,半联结(Semi-Join)和反联结(Anti-Join)是两种特殊的联结方式,它们在处理多表查询时能提供高效的数据筛选。半联结用于找出那些在一张表中存在,而在另一张表中至少有一个匹配的记录的行,而反...
分布式SQL节点负责生成和执行分布式执行计划,可以并行执行SQL语句,同时具备分布式事务协调能力,处理如`orderby`、`limit`、`groupby`、`aggregation`和`join`等复杂的操作。这些节点设计为无中心化,确保系统的高...
`always_semi_join`则影响EXISTS子查询的执行,当没有索引时,半连接可能会提高性能。 2. **aq_tm_processes**:此参数用于启用队列消息的时间监控,其值决定可以监视的消息数量,影响应用程序的延迟和失效特性。 ...
另外,SQL查询的性能也有所提高,例如通过改进的查询优化器,能够更好地处理JOIN操作和子查询。 二、存储引擎的改进 InnoDB存储引擎在5.6版本中得到了重大优化。表空间管理更高效,支持在线DDL(Data Definition ...
`always_anti_join` 控制如何处理NOT IN子查询,可以选择NESTED_LOOPS(嵌套循环)、MERGE(合并)或HASH方法。`always_semi_join`则涉及EXISTS子查询的优化,如果在限制子查询的列上有索引,使用半连接可以提高性能...