Skip to content

DM SQL执行计划

执行计划的作用

  • 分析查询性能:识别SQL语句的性能瓶颈
  • 优化查询语句:根据执行计划调整SQL语句
  • 验证索引效果:确认索引是否被有效使用
  • 理解查询逻辑:了解数据库如何执行SQL语句
  • 预测执行成本:评估SQL语句的执行开销

执行计划的组成部分

  • 操作类型:如全表扫描、索引扫描、连接操作等
  • 操作对象:如表名、索引名
  • 访问方法:如顺序访问、随机访问
  • 连接方式:如嵌套循环连接、哈希连接、排序合并连接
  • 排序方式:如升序、降序
  • 成本估算:执行计划的估计成本
  • 行数估算:估计返回的行数

执行计划生成原理

DM数据库的执行计划由优化器生成,优化器根据以下因素生成最优执行计划:

优化器类型

DM数据库支持两种优化器:

  • 基于规则的优化器(RBO):根据预定义的规则生成执行计划
  • 基于成本的优化器(CBO):根据统计信息和成本模型生成执行计划

优化器选择的影响因素

  1. 表的统计信息:包括表的行数、列的基数、直方图等
  2. 索引信息:索引的类型、大小、选择性等
  3. SQL语句的复杂度:简单查询和复杂查询的优化策略不同
  4. 系统资源状况:CPU、内存、IO等资源状况
  5. 初始化参数:如优化器模式、并行度等
  6. 表的大小:大表和小表的访问方式不同

执行计划生成流程

  1. 解析SQL语句:将SQL语句解析为内部表示
  2. 生成逻辑执行计划:根据SQL逻辑生成初步的执行计划
  3. 优化逻辑执行计划:应用优化规则优化执行计划
  4. 生成物理执行计划:将逻辑执行计划转换为物理执行计划
  5. 选择最优执行计划:根据成本模型选择最优执行计划
  6. 执行并监控:执行SQL语句并监控执行情况

查看执行计划的方法

使用EXPLAIN语句

EXPLAIN语句是查看执行计划的最常用方法,它可以显示SQL语句的执行计划,但不实际执行SQL语句。

基本语法

sql
EXPLAIN [PLAN FOR] sql_statement;

使用示例

sql
-- 查看简单查询的执行计划
EXPLAIN SELECT * FROM emp WHERE deptno = 10;

-- 查看连接查询的执行计划
EXPLAIN SELECT e.*, d.* FROM emp e JOIN dept d ON e.deptno = d.deptno;

-- 查看包含子查询的执行计划
EXPLAIN SELECT * FROM emp WHERE deptno IN (SELECT deptno FROM dept WHERE loc = 'NEW YORK');

-- 查看包含聚合函数的执行计划
EXPLAIN SELECT deptno, COUNT(*) FROM emp GROUP BY deptno;

使用EXPLAIN PLAN语句

EXPLAIN PLAN语句可以将执行计划存储到指定的表中,便于后续分析。

基本语法

sql
EXPLAIN PLAN [SET STATEMENT_ID = 'string'] FOR sql_statement;

使用示例

sql
-- 将执行计划存储到默认表
EXPLAIN PLAN FOR SELECT * FROM emp WHERE deptno = 10;

-- 查看存储的执行计划
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());

-- 使用自定义STATEMENT_ID
EXPLAIN PLAN SET STATEMENT_ID = 'test_plan' FOR SELECT * FROM emp;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, 'test_plan'));

使用V$SQL_PLAN视图

V$SQL_PLAN视图存储了已执行SQL语句的执行计划,可以查看历史执行计划。

sql
-- 查看所有SQL执行计划
SELECT * FROM V$SQL_PLAN;

-- 查看特定SQL的执行计划
SELECT * FROM V$SQL_PLAN WHERE SQL_ID = '1234567890ABCDEF' ORDER BY ID;

-- 查看使用索引的SQL执行计划
SELECT DISTINCT SQL_ID, OPERATION, OPTIONS, OBJECT_NAME 
FROM V$SQL_PLAN 
WHERE OPERATION LIKE '%INDEX%';

使用V$SQL_PLAN_STATISTICS_ALL视图

V$SQL_PLAN_STATISTICS_ALL视图提供了执行计划的实际执行统计信息。

sql
-- 查看执行计划的实际执行统计
SELECT * FROM V$SQL_PLAN_STATISTICS_ALL WHERE SQL_ID = '1234567890ABCDEF' ORDER BY ID;

使用DM管理工具

  1. 启动DM管理工具,连接到数据库实例
  2. 在SQL编辑器中输入SQL语句
  3. 点击"执行计划"按钮(或按F5键)
  4. 在执行计划窗口中查看执行计划
  5. 点击执行计划节点查看详细信息

使用DM性能监控工具

  1. 启动DM性能监控工具,连接到数据库实例
  2. 在左侧导航树中选择"性能" -> "SQL监控"
  3. 在右侧窗口中查看正在执行的SQL语句
  4. 点击SQL语句,查看其执行计划
  5. 分析执行计划并进行优化

执行计划结构分析

执行计划的基本结构

DM数据库的执行计划通常以树状结构显示,每个节点代表一个操作,包含以下信息:

  • ID:操作节点的唯一标识符
  • PARENT_ID:父操作节点的ID
  • OPERATION:操作类型
  • OPTIONS:操作选项
  • OBJECT_NAME:操作对象名称
  • OBJECT_TYPE:操作对象类型
  • COST:估计成本
  • CARDINALITY:估计返回行数
  • BYTES:估计返回字节数
  • ACCESS_PREDICATES:访问谓词
  • FILTER_PREDICATES:过滤谓词

执行计划示例分析

以一个简单的查询为例,分析执行计划结构:

sql
EXPLAIN SELECT * FROM emp WHERE deptno = 10 AND sal > 2000;

执行计划输出:

ID | PARENT_ID | OPERATION         | OPTIONS         | OBJECT_NAME | OBJECT_TYPE | COST | CARDINALITY | BYTES | ACCESS_PREDICATES       | FILTER_PREDICATES
---|-----------|-------------------|-----------------|-------------|-------------|------|-------------|-------|-------------------------|-------------------
1  | 0         | SELECT STATEMENT  |                 |             |             | 5    | 2           | 200   |                         |
2  | 1         | TABLE ACCESS      | BY INDEX ROWID  | EMP         | TABLE       | 5    | 2           | 200   |                         | SAL > 2000
3  | 2         | INDEX RANGE SCAN  |                 | IDX_EMP_DEPTNO | INDEX       | 3    | 5           |       | DEPTNO = 10             |

执行计划分析

  1. SELECT STATEMENT:根节点,表示SELECT语句
  2. TABLE ACCESS BY INDEX ROWID:通过索引ROWID访问表EMP
    • FILTER_PREDICATES:SAL > 2000,表示在表访问后过滤sal > 2000的行
  3. INDEX RANGE SCAN:对索引IDX_EMP_DEPTNO进行范围扫描
    • ACCESS_PREDICATES:DEPTNO = 10,表示使用索引访问deptno = 10的行
    • 估计返回5行,然后过滤出sal > 2000的行,最终返回2行

执行计划操作类型

表访问操作

FULL TABLE SCAN

描述:全表扫描,扫描表的所有行 适用场景:表很小,或者没有合适的索引 示例

sql
EXPLAIN SELECT * FROM emp;

TABLE ACCESS BY INDEX ROWID

描述:通过索引ROWID访问表 适用场景:使用索引找到ROWID,然后访问表数据 示例

sql
EXPLAIN SELECT * FROM emp WHERE deptno = 10;

TABLE ACCESS BY GLOBAL INDEX ROWID

描述:通过全局索引ROWID访问分区表 适用场景:分区表的全局索引访问

索引访问操作

INDEX FULL SCAN

描述:全索引扫描,扫描索引的所有行 适用场景:索引包含查询所需的所有列(覆盖索引) 示例

sql
EXPLAIN SELECT deptno, COUNT(*) FROM emp GROUP BY deptno;

INDEX RANGE SCAN

描述:索引范围扫描,扫描索引的特定范围 适用场景:等值查询、范围查询 示例

sql
EXPLAIN SELECT * FROM emp WHERE deptno = 10;

INDEX UNIQUE SCAN

描述:唯一索引扫描,扫描唯一索引的一行 适用场景:唯一索引的等值查询 示例

sql
EXPLAIN SELECT * FROM emp WHERE empno = 7839;

INDEX SKIP SCAN

描述:索引跳跃扫描,适用于复合索引 适用场景:复合索引的前缀列没有指定条件

连接操作

NESTED LOOPS

描述:嵌套循环连接 适用场景:小表连接,或有合适索引的连接 示例

sql
EXPLAIN SELECT e.*, d.* FROM emp e JOIN dept d ON e.deptno = d.deptno;

HASH JOIN

描述:哈希连接 适用场景:大表连接,没有合适索引 示例

sql
EXPLAIN SELECT * FROM emp e JOIN dept d ON e.deptno = d.deptno;

SORT MERGE JOIN

描述:排序合并连接 适用场景:两个表都已排序,或需要排序输出

排序操作

SORT AGGREGATE

描述:聚合排序,用于聚合函数 适用场景:COUNT、SUM、AVG等聚合函数 示例

sql
EXPLAIN SELECT deptno, COUNT(*) FROM emp GROUP BY deptno;

SORT ORDER BY

描述:排序操作,用于ORDER BY子句 适用场景:ORDER BY子句 示例

sql
EXPLAIN SELECT * FROM emp ORDER BY deptno, sal DESC;

SORT GROUP BY

描述:分组排序,用于GROUP BY子句 适用场景:GROUP BY子句 示例

sql
EXPLAIN SELECT deptno, job, COUNT(*) FROM emp GROUP BY deptno, job;

执行计划优化技巧

1. 识别全表扫描

问题:全表扫描(FULL TABLE SCAN)通常效率较低,特别是对于大表 解决方法

  • 添加合适的索引
  • 优化WHERE条件,减少返回行数
  • 考虑使用分区表

2. 优化索引使用

问题:索引没有被有效使用 解决方法

  • 检查索引是否存在
  • 检查WHERE条件是否使用了索引列
  • 避免在索引列上使用函数
  • 考虑修改索引列顺序

3. 优化连接操作

问题:连接操作效率低下 解决方法

  • 为连接列添加索引
  • 优化连接顺序
  • 选择合适的连接方式
  • 考虑使用并行连接

4. 优化排序操作

问题:排序操作消耗大量资源 解决方法

  • 避免不必要的排序
  • 使用索引避免排序
  • 优化ORDER BY和GROUP BY子句
  • 考虑增加排序区大小

5. 优化子查询

问题:子查询效率低下 解决方法

  • 考虑使用连接替代子查询
  • 优化子查询的WHERE条件
  • 考虑使用物化视图

6. 优化聚合操作

问题:聚合操作效率低下 解决方法

  • 为聚合列添加索引
  • 考虑使用分区表
  • 考虑使用并行聚合
  • 优化GROUP BY子句

执行计划相关视图

V$SQL_PLAN

作用:存储已执行SQL语句的执行计划 主要列:SQL_ID, PLAN_ID, OPERATION, OPTIONS, OBJECT_NAME, COST, CARDINALITY

V$SQL_PLAN_STATISTICS_ALL

作用:提供执行计划的实际执行统计信息 主要列:SQL_ID, PLAN_ID, OPERATION, ACTUAL_ROWS, ACTUAL_TIME, PHYSICAL_READS

V$SQL

作用:存储已执行SQL语句的信息 主要列:SQL_ID, SQL_TEXT, EXECUTIONS, TOTAL_TIME, ELAPSED_TIME

V$SQL_STATISTICS

作用:存储SQL语句的执行统计信息 主要列:SQL_ID, SQL_TEXT, EXECUTIONS, TOTAL_TIME, CPU_TIME, IO_WAIT_TIME

DBA_HIST_SQL_PLAN

作用:存储历史SQL执行计划 主要列:SQL_ID, PLAN_HASH_VALUE, OPERATION, OPTIONS, OBJECT_NAME

执行计划最佳实践

1. 定期分析执行计划

  • 定期分析频繁执行的SQL语句的执行计划
  • 分析AWR报告中的TOP SQL执行计划
  • 在SQL语句上线前分析执行计划

2. 使用绑定变量

  • 使用绑定变量可以提高执行计划的重用率
  • 避免硬解析,提高SQL执行效率

3. 收集统计信息

  • 定期收集表和索引的统计信息
  • 确保优化器有准确的统计信息生成最优执行计划

4. 测试不同执行计划

  • 使用HINT提示强制使用不同的执行计划
  • 比较不同执行计划的性能差异
  • 选择最优执行计划

5. 监控执行计划变化

  • 监控执行计划的变化
  • 分析执行计划变化的原因
  • 及时调整SQL语句或索引

6. 结合实际执行统计

  • 不仅要看估计执行计划,还要看实际执行统计
  • 比较估计值和实际值的差异
  • 调整统计信息或执行计划

版本差异说明

版本主要变化
DM 7支持基本的执行计划查看和分析功能
DM 8增强了执行计划功能,支持更多操作类型和优化策略
DM 8.1优化了执行计划的生成性能,支持并行执行计划

常见问题(FAQ)

Q1: 为什么执行计划与实际执行情况不符?

A1: 执行计划与实际执行情况不符的原因:

  • 统计信息不准确:需要重新收集统计信息
  • 绑定变量窥探:使用绑定变量可能导致执行计划不准确
  • 系统资源变化:系统资源变化可能影响执行计划
  • 执行计划过时:需要重新生成执行计划

Q2: 如何强制使用特定的执行计划?

A2: 可以使用HINT提示强制使用特定的执行计划:

sql
-- 强制使用索引
SELECT /*+ INDEX(emp idx_emp_deptno) */ * FROM emp WHERE deptno = 10;

-- 强制使用哈希连接
SELECT /*+ USE_HASH(e d) */ e.*, d.* FROM emp e JOIN dept d ON e.deptno = d.deptno;

Q3: 如何查看执行计划的成本计算?

A3: 可以通过以下方法查看执行计划的成本计算:

  • 使用EXPLAIN语句查看COST列
  • 分析V$SQL_PLAN视图的COST列
  • 使用DM管理工具查看执行计划的成本信息

Q4: 执行计划中的"CARDINALITY"和"ACTUAL_ROWS"有什么区别?

A4: "CARDINALITY"是优化器估计的行数,"ACTUAL_ROWS"是实际执行返回的行数。两者的差异反映了优化器统计信息的准确性。

Q5: 如何优化复杂查询的执行计划?

A5: 优化复杂查询执行计划的方法:

  • 分解复杂查询为多个简单查询
  • 优化每个子查询的执行计划
  • 考虑使用物化视图
  • 调整查询逻辑
  • 添加合适的索引

Q6: 如何识别执行计划中的性能瓶颈?

A6: 识别执行计划性能瓶颈的方法:

  • 查看执行计划的成本分布
  • 分析实际执行统计信息
  • 关注耗时最长的操作
  • 查看等待事件信息

Q7: 为什么添加索引后执行计划没有使用?

A7: 添加索引后执行计划没有使用的原因:

  • 索引选择性不高:索引的选择性太低,优化器认为全表扫描更高效
  • 统计信息不准确:需要重新收集统计信息
  • SQL语句没有使用索引列:WHERE条件中没有使用索引列
  • 索引列上使用了函数:索引列上的函数导致索引失效

Q8: 如何比较不同执行计划的性能?

A8: 比较不同执行计划性能的方法:

  • 比较执行计划的成本
  • 比较实际执行时间
  • 比较资源消耗(CPU、内存、IO)
  • 比较返回行数

Q9: 如何查看历史执行计划?

A9: 查看历史执行计划的方法:

  • 查询DBA_HIST_SQL_PLAN视图
  • 分析AWR报告中的执行计划
  • 使用DM性能监控工具查看历史执行计划

Q10: 执行计划中的"BY INDEX ROWID"和"INDEX RANGE SCAN"有什么区别?

A10: "INDEX RANGE SCAN"是索引范围扫描,用于找到符合条件的ROWID;"BY INDEX ROWID"是通过ROWID访问表数据。两者通常一起使用,先通过索引找到ROWID,然后通过ROWID访问表数据。

在实际工作中,DBA应该结合多种方法查看执行计划,包括EXPLAIN语句、系统视图、管理工具等,并结合实际执行统计信息,全面分析执行计划。同时,需要定期收集统计信息,使用绑定变量,优化索引设计,确保优化器生成最优执行计划。

通过合理使用执行计划,DBA可以显著提高DM数据库的查询性能,降低系统资源消耗,为业务提供高效、稳定的数据服务。