暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

Oracle Administrator's Guide(Oracle 19c):9.5 Resolving Problems

原创 Ryan Bai 2026-05-31
74

本节介绍如何使用顾问工具(如 SQL Repair Advisor 和 Data Recovery Advisor)以及资源管理工具(如 Resource Manager 和相关 API)解决数据库问题。

使用 SQL Repair Advisor 修复 SQL 故障

在极少数情况下,SQL 语句失败并出现严重错误,您可以运行 SQL Repair Advisor 来尝试修复失败的语句。

关于 SQL Repair Advisor

在 SQL 语句出现严重错误失败后运行 SQL Repair Advisor。

顾问分析语句,并在许多情况下推荐修补程序来修复语句。如果实现了建议,则应用的 SQL 补丁会使查询优化器为将来的执行选择替代执行计划,从而避免失败。

您可以使用 Cloud Control 或 DBMS_SQLDIAG 包子程序运行 SQL Repair Advisor。

使用 Cloud Control 运行 SQL Repair Advisor

您可以在 Cloud Control 的 Support Workbench 的 Problem Details 页面中运行 SQL Repair Advisor。

通常,当您已经收到由SQL语句引起的严重错误的通知,并且您遵循“About Investigating, Reporting, and Resolving a Problem”中描述的工作流程时,您就可以这样做。

使用 Cloud Control 运行 SQL Repair Advisor:

  1. 访问 Problem Details 页面,查看与失败的 SQL 语句相关的问题。

  2. 在 Investigate and Resolve 部分中,在 Resolve 标题下,单击 SQL Repair Advisor

    Description of advisor_access1.gif follows

  3. 在 SQL Repair Advisor 页面上,完成以下步骤:

    1. 如果需要,修改预设任务名称,可选地输入任务描述,修改或清除顾问任务的可选时间限制,并调整设置以安排顾问立即或在未来的日期和时间运行。
    2. 点击 Submit.

    出现 “Processing” 页面。经过短暂的延迟后,出现 SQL Repair Results 页面。

    Description of sql_repair_advisor_results.gif follows

    SQL Patch 列中的复选标记表示存在建议。此列中缺少复选标记意味着 SQL Repair Advisor 无法为该 SQL 语句设计补丁。

  4. 如果存在推荐(SQL Patch 列中有一个复选标记),则单击 View 以查看推荐。

    出现修复建议页面,显示该语句的推荐补丁。

  5. 点击 Implement.

    返回 SQL Repair Results 页面,显示一条确认消息。

  6. (可选)单击 Verify using SQL Worksheet ,在SQL工作表中运行该语句,验证补丁是否成功修复了该语句。

使用 DBMS_SQLDIAG 包子程序运行 SQL Repair Advisor

您可以使用 DBMS_SQLDIAG 包子程序运行 SQL Repair Advisor。

通常,当您收到由 SQL 语句引起的严重错误的通知,并且您遵循“About Investigating, Reporting, and Resolving a Problem”中描述的工作流程时,您可以这样做。

通过分别使用 DBMS_SQLDIAG 包子程序 CREATE_DIAGNOSIS_TASKEXECUTE_DIAGNOSIS_TASK 创建和执行诊断任务来运行 SQL Repair Advisor。SQL Repair Advisor 首先重现严重错误,然后尝试以 SQL 补丁的形式生成一个解决方案,您可以使用 ACCEPT_SQL_PATCH 子程序应用该解决方案。

使用 DBMS_SQLDIAG 包子程序运行 SQL Repair Advisor:

  1. 识别有问题的 SQL 语句

    考虑给出一个严重错误的SQL语句:

    DELETE FROM t t1 WHERE t1.a = 'a' AND ROWID <> (SELECT MAX(ROWID) FROM t t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.d = t2.d)

    您可以使用 SQL Repair Advisor 修复此严重错误。

  2. 创建诊断任务

    运行 DBMS_SQLDIAG.CREATE_DIAGNOSIS_TASK。您可以指定可选的任务名称、顾问任务的可选时间限制和问题类型。在下例中,我们指定 SQL 文本,任务名称为“error_task”,问题类型为“DBMS_SQLDIAG.PROBLEM_TYPE_COMPILATION_ERROR”。

    DECLARE
      rep_out   CLOB;
      t_id      VARCHAR2(50);
    BEGIN
      t_id := DBMS_SQLDIAG.CREATE_DIAGNOSIS_TASK (
               sql_text => 'DELETE FROM t t1
                            WHERE t1.a = ''a'' AND
                                  ROWID <> (SELECT MAX(ROWID)
                                            FROM t t2
                                            WHERE t1.a = t2.a AND
                                                  t1.b = t2.b AND
                                                  t1.d = t2.d)',
               task_name => 'error_task',
               problem_type => DBMS_SQLDIAG.PROBLEM_TYPE_COMPILATION_ERROR);
    
  3. 执行诊断任务
    要执行 SQL Repair Advisor 的解决方案生成和分析阶段,可以运行 DBMS_SQLDIAG.EXECUTE_DIAGNOSIS_TASK ,使用 CREATE_DIAGNOSIS_TASK 返回的任务 ID。经过短暂的延迟后,SQL Repair Advisor 返回。作为其执行的一部分,SQL Repair Advisor 保留其发现的记录,可以通过 SQL Repair Advisor 的报告功能访问这些记录。

    DBMS_SQLDIAG.EXECUTE_DIAGNOSIS_TASK (t_id);
    
  4. 生成诊断任务的报表

    使用 DBMS_SQLDIAG.REPORT_DIAGNOSIS_TASK 访问诊断任务的分析。如果 SQL Repair Advisor 能够找到解决方案,它会建议使用 SQL 补丁。SQL 补丁类似于 SQL 配置文件,但与 SQL 配置文件不同的是,它用于解决编译或执行错误。

    rep_out := DBMS_SQLDIAG.REPORT_DIAGNOSIS_TASK (t_id, DBMS_SQLDIAG.TYPE_TEXT);
    DBMS_OUTPUT.PUT_LINE ('Report : ' ||  rep_out);
    END;
    /
    
  5. 使用补丁
    如果报告中有补丁建议,您可以运行 DBMS_SQLDIAG.ACCEPT_SQL_PATCH 接受补丁。此过程将任务名称作为参数。

    EXECUTE DBMS_SQLDIAG.ACCEPT_SQL_PATCH(task_name => 'error_task', task_owner => 'SYS', replace => TRUE);
    
  6. 测试补丁

    既然已经接受了补丁,就可以重新运行 SQL 语句了。这一次,它不会给你临界错误。如果对该语句运行 explain plan,您将看到使用了一个 SQL 补丁来生成该计划。

    DELETE FROM t t1 WHERE t1.a = 'a' AND ROWID <> (SELECT max(rowid) FROM t t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.d = t2.d);

使用 Cloud Control 查看、禁用或删除 SQL 补丁

在使用 SQL Repair Advisor 应用 SQL 补丁后,您可以查看它以确认其存在、禁用它或使用 Cloud Control 删除它。禁用或删除补丁的一个原因是,如果您安装了 Oracle 数据库的更新版本,该版本修复了导致补丁 SQL 语句失败的错误。

使用 Cloud Control 查看、禁用或删除 SQL 补丁:

  1. 进入 Cloud Control 中的 Database Home 页面。

  2. 从 Performance 菜单中选择 SQL,然后选择 SQL Plan Control.

    出现 SQL Plan Control 页面。

  3. 单击 SQL Patch ,显示 SQL Patch 子界面。

    SQL Patch 子页面显示数据库中所有SQL补丁。

  4. 通过检查相关的 SQL 文本来定位所需的补丁。

    单击 SQL 文本以查看语句的完整文本。查看完 SQL 文本后,单击 Return.

  5. 在 SQL Patch 子页面中,选中补丁,然后单击 Disable,即可禁用该补丁。

    出现确认消息,补丁状态变为 DISABLED。您可以稍后通过选择它并单击 **Enable **来重新启用补丁。

  6. 要删除补丁,请选择它,然后单击 Drop

    出现确认消息。

使用 DBMS_SQLDIAG 包子程序禁用或删除SQL补丁

在使用 SQL Repair Advisor 应用SQL补丁之后,可以使用 DBMS_SQLDIAG 包子程序禁用或删除它。禁用或删除补丁的一个原因是,如果您安装了Oracle数据库的更新版本,该版本修复了导致补丁 SQL 语句失败的错误。

使用 DBMS_SQLDIAG 包子程序禁用 SQL 补丁:

运行 DBMS_SQLDIAG.ALTER_SQL_PATCH 过程,指定要禁用的补丁名称,状态值为 DISABLED.

禁用 SQL 补丁 sql_patch_12345,示例如下。

EXEC DBMS_SQLDIAG.ALTER_SQL_PATCH('sql_patch_12345', 'STATUS', 'DISABLED');

使用 DBMS_SQLDIAG 包子程序删除 SQL 补丁:

运行 DBMS_SQLDIAG.DROP_SQL_PATCH 过程,指定要删除的补丁名称。补丁名称可以从解释计划部分或通过查询 DBA_SQL_PATCHES 视图获得。

下面的示例删除SQL补丁 sql_patch_12345

EXEC DBMS_SQLDIAG.DROP_SQL_PATCH('sql_patch_12345');

使用 DBMS_SQLDIAG 包子程序导出和导入补丁

使用 SQL Repair Advisor 创建的补丁可以从一个系统导出,并使用 DBMS_SQLDIAG 包子程序导入到另一个系统。

补丁可以从一个系统导出,并通过使用 staging 表导入到另一个系统。与 SQL 诊断集一样,插入到 staging 表中的操作称为 “pack”,从 staging 表数据创建补丁的操作称为 “unpack”。

使用 DBMS_SQLDIAG 包子程序导出和导入补丁:

  1. 通过调用 DBMS_SQLDIAG.CREATE_STGTAB_SQLPATCH 创建一个由用户 ‘SH’ 拥有的 staging 表:

    EXEC DBMS_SQLDIAG.CREATE_STGTAB_SQLPATCH(
        table_name          =>  'STAGING_TABLE',
        schema_name         =>  'SH'); 
    
  2. 调用 DBMS_SQLDIAG.PACK_STGTAB_SQLPATCH 一次或多次将SQL补丁数据写入 staging 表。在这种情况下,将 DEFAULT 类别下的所有SQL补丁的数据复制到当前模式所有者拥有的 staging 表中:

    EXEC DBMS_SQLDIAG.PACK_STGTAB_SQLPATCH(
        staging_table_name  =>  'STAGING_TABLE'); 
    
  3. 在这种情况下,只有一个 SQL 补丁 SP_FIND_EMPLOYEE 被复制到当前模式所有者拥有的 staging 表中:

    EXEC DBMS_SQLDIAG.PACK_STGTAB_SQLPATCH(
        patch_name          =>  'SP_FIND_EMPLOYEE',
        staging_table_name  =>  'STAGING_TABLE'); 
    

    然后可以使用数据泵、import/export 命令或使用数据库链接将 staging 表移动到另一个系统。

  4. 调用 DBMS_SQLDIAG.UNPACK_STGTAB_SQLPATCH 从暂存表中的补丁数据在新系统上创建 SQL 补丁。在这种情况下,将存储在 staging 表中的 SP_FIND_EMPLOYEE 补丁的数据中的名称更改为 ‘SP_FIND_EMP_PROD’:

    exec dbms_sqldiag.remap_stgtab_sqlpatch(
       old_patch_name      =>  'SP_FIND_EMPLOYEE',
       new_patch_name      =>  'SP_FIND_EMP_PROD', 
    

使用 Data Recovery Advisor 修复数据损坏

您可以使用 Data Recovery Advisor 修复数据块损坏、撤消损坏、数据字典损坏等。

Data Recovery Advisor 与 Enterprise Manager Support Workbench(Support Workbench)、运行状况监视器和 RMAN 实用程序集成,以显示数据损坏问题、评估每个问题的严重程度(严重、高优先级、低优先级)、描述问题的影响、推荐修复选项、对客户选择的选项进行可行性检查,并自动执行修复过程。

Cloud Control 在线帮助提供了如何使用 Data Recovery Advisor 的详细信息。本节描述如何从 Support Workbench 访问顾问。

当您查看与数据损坏或其他数据故障相关的运行状况检查器发现时,Support Workbench 会自动推荐并访问 Data Recovery Advisor。Data Recovery Advisor 也可以从 Advisor Central 页面获得。

访问 Cloud Control 中的 Data Recovery Advisor:

  1. 进入 Cloud Control 中的 Database Home 页面。

    只有当您以 SYSDBA 身份连接时,Data Recovery Advisor 才可用。

  2. 从Oracle数据库菜单中,选择 Diagnostics,然后选择 Support Workbench.

  3. 单击 Checker Findings.

    将出现 Checker Findings 子页面。

    Description of dra_access_2.gif follows

  4. 选择一个或多个数据损坏发现,然后单击 Launch Recovery Advisor.

隔离消耗过多系统资源的 SQL 语句的执行计划

从 Oracle Database 19c 开始,可以使用 SQL 隔离基础结构(SQL 隔离)隔离因消耗 Oracle 数据库中过多系统资源而由资源管理器终止的 SQL 语句的执行计划。单个 SQL 语句可能有多个执行计划,如果它试图使用隔离的执行计划,则不允许该 SQL 语句运行,从而防止数据库性能下降。

关于 SQL 语句执行计划的隔离

可以使用 SQL 隔离基础结构(SQL 隔离)隔离因消耗 Oracle 数据库中过多系统资源而由资源管理器终止的 SQL 语句的执行计划。不允许再次运行此类 SQL 语句的隔离执行计划,从而防止数据库性能下降。

使用资源管理器,您可以配置 SQL 语句消耗系统资源的限制(Resource Manager 阈值)。资源管理器终止超过资源管理器阈值的 SQL 语句。在早期的 Oracle 数据库版本中,如果被资源管理器终止的 SQL 语句再次运行,资源管理器允许它再次运行,并在超过资源管理器的阈值时再次终止它。因此,允许这样的 SQL 语句再次运行是对系统资源的浪费。

从 Oracle Database 19c 开始,可以使用 SQL 隔离自动隔离由资源管理器终止的 SQL 语句的执行计划,从而不允许它们再次运行。定期将 SQL 隔离信息持久化到数据字典中。当资源管理器终止 SQL 语句时,可能需要几分钟的时间才能隔离该语句。

此外,通过使用 DBMS_SQLQ 包子程序指定消耗各种系统资源的阈值(类似于资源管理器阈值),SQL Quarantine 还可用于为 SQL 语句的执行计划创建隔离配置。这些阈值称为隔离阈值。如果任何资源管理器阈值等于或小于 SQL 语句的隔离配置中指定的隔离阈值,则不允许运行 SQL 语句(如果 SQL 语句使用其隔离配置中指定的执行计划)。

以下是使用 DBMS_SQLQ 包子程序为 SQL 语句的执行计划手动设置隔离阈值的步骤:

  1. 为 SQL 语句的执行计划创建隔离配置
  2. 在隔离配置中指定隔离阈值

还可以使用 DBMS_SQLQ 包子程序执行以下与隔离配置相关的操作:

  • 启用或禁用隔离配置
  • 删除隔离配置
  • 将隔离配置从一个数据库传输到另一个数据库

例如,考虑一个资源管理器的资源计划,它将 SQL 语句的执行时间限制为 10 秒(资源管理器阈值)。考虑一个 SQL 语句 Q1,它的资源计划是应用程序。当 Q1 超过 10 秒的执行时间时,它将被资源管理器终止。然后,SQL Quarantine 为特定于该执行计划的 Q1 创建隔离配置,并将此 10 秒的执行时间存储为隔离配置中的隔离阈值。

如果使用相同的执行计划再次执行 Q1,并且资源管理器阈值仍然为 10 秒,则 SQL 隔离不允许执行 Q1,因为它引用 10 秒的隔离阈值来确定 Q1 最终将由资源管理器终止,因为 Q1 至少需要 10 秒才能执行。

如果将资源管理器阈值更改为 5 秒,并且使用相同的执行计划再次执行 Q1,则 SQL 隔离不允许执行 Q1,因为它引用 10 秒的隔离阈值来确定 Q1 最终将由资源管理器终止,因为 Q1 至少需要 10 秒才能执行。

如果将资源管理器阈值更改为 15 秒,并且使用相同的执行计划再次执行 Q1,则 SQL 隔离允许 Q1 执行,因为它引用 10 秒的隔离阈值来确定 Q1 至少需要 10 秒才能执行,但 Q1 有可能在 15 秒内完成其执行。

为 SQL 语句的执行计划创建隔离配置

可以使用以下任何一个 DBMS_SQLQ 包函数 – CREATE_QUARANTINE_BY_SQL_IDCREATE_QUARANTINE_BY_SQL_TEXT 为SQL语句的执行计划创建隔离配置。

以下示例为 SQL ID 为 8vu7s907prbgr 的SQL语句创建散列值为 3488063716 的执行计划的隔离配置:

DECLARE
    quarantine_config VARCHAR2(30);
BEGIN
    quarantine_config := DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_ID(
                            SQL_ID => '8vu7s907prbgr', 
                            PLAN_HASH_VALUE => '3488063716');
END;
/

如果未指定执行计划或将其指定为 NULL,则隔离配置将应用于 SQL 语句的所有执行计划,但已经为其创建了特定于执行计划的隔离配置的执行计划除外。

以下示例为SQL ID为 152sukb473gsk 的 SQL 语句的所有执行计划创建隔离配置:

DECLARE
    quarantine_config VARCHAR2(30);
BEGIN
    quarantine_config := DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_ID(
                            SQL_ID => '152sukb473gsk');
END;
/

以下示例为 SQL 语句 select count(*) from emp 的所有执行计划创建隔离配置:

DECLARE
    quarantine_config VARCHAR2(30);
BEGIN
    quarantine_config := DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_TEXT(
                            SQL_TEXT => to_clob('select count(*) from emp'));
END;
/

CREATE_QUARANTINE_BY_SQL_IDCREATE_QUARANTINE_BY_SQL_TEXT 函数返回隔离配置的名称,该名称可用于使用 DBMS_SQLQ.ALTER_QUARANTINE 过程为 SQL 语句的执行计划指定隔离阈值。

在隔离配置中指定隔离阈值

为 SQL 语句的执行计划创建隔离配置后,可以使用 DBMS_SQLQ.ALTER_QUARANTINE 过程为其指定隔离阈值。当任何资源管理器阈值等于或小于 SQL 语句的隔离配置中指定的隔离阈值时,如果 SQL 语句使用其隔离配置中指定的执行计划,则不允许运行该SQL语句。

可以在隔离配置中为以下资源指定隔离阈值,使用 DBMS_SQLQ.ALTER_QUARANTINE 的过程:

  • CPU 时间
  • Elapsed 时间
  • I/O(MB)
  • 物理I/O请求数
  • 逻辑I/O请求数

在下例中,对于隔离配置 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4,为 CPU 时间指定的隔离阈值为 5 秒,经过时间为 10 秒。

BEGIN
    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'CPU_TIME',
       PARAMETER_VALUE => '5');

    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'ELAPSED_TIME',
       PARAMETER_VALUE => '10');
END;
/

使用此隔离配置中指定的执行计划执行 SQL 语句时,如果资源管理器的 CPU 时间阈值为 5 秒或更短,或者运行时间为 10 秒或更短,则不允许运行 SQL 语句。

查询隔离配置的隔离阈值

可以使用DBMS_SQLQ.GET_PARAM_VALUE_QUARANTINE 函数查询隔离配置的隔离阈值。以下示例返回隔离配置 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4 的 CPU 时间消耗的隔离阈值:

DECLARE
    quarantine_config_setting_value VARCHAR2(30);
BEGIN
    quarantine_config_setting_value := 
        DBMS_SQLQ.GET_PARAM_VALUE_QUARANTINE(
              QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
              PARAMETER_NAME  => 'CPU_TIME');
END;
/

从隔离配置中删除隔离阈值

可以通过指定 DBMS_SQLQ.DROP_THRESHOLD 作为 PARAMETER_VALUE 的值从隔离配置中删除隔离阈值。以下示例从隔离配置 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4 中删除 CPU 时间消耗的隔离阈值:

BEGIN
    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'CPU_TIME',
       PARAMETER_VALUE => DBMS_SQLQ.DROP_THRESHOLD);
END;
/

启用和禁用隔离配置

可以使用 DBMS_SQLQ.ALTER_QUARANTINE 过程启用或禁用隔离配置。创建隔离配置时默认启用隔离配置。

以下示例禁用名称为 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4 的隔离配置:

BEGIN
    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'ENABLED',
       PARAMETER_VALUE => 'NO');
END;
/

以下示例启用名称为 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4 的隔离配置:

BEGIN
    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'ENABLED',
       PARAMETER_VALUE => 'YES');
END;
/

查看隔离配置的详细信息

可以查询 DBA_SQL_QUARANTINE 视图以获取所有隔离配置的详细信息。

DBA_SQL_QUARANTINE 视图包含有关每个隔离配置的以下信息:

  • 隔离配置名称
  • 适用隔离配置的 SQL 语句
  • 隔离配置适用的执行计划的哈希值
  • 隔离配置的状态(启用或禁用)
  • 隔离配置的自动清除状态(yes 或 no)
  • 为隔离配置指定的隔离阈值:
    • CPU 时间
    • Elapsed 时间
    • I/O(MB)
    • 物理 I/O 请求数
    • 逻辑 I/O 请求数
  • 创建隔离配置的日期和时间
  • 上次执行隔离配置的日期和时间

删除隔离配置

未使用的隔离配置将在 53 周后自动清除或删除。还可以使用 DBMS_SQLQ.DROP_QUARANTINE 过程。可以使用 DBMS_SQLQ.ALTER_QUARANTINE 过程禁用隔离配置的自动删除。

以下示例禁用自动删除隔离配置 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4

BEGIN
    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'AUTOPURGE',
       PARAMETER_VALUE => 'NO');
END;
/

以下示例启用自动删除隔离配置 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4

BEGIN
    DBMS_SQLQ.ALTER_QUARANTINE(
       QUARANTINE_NAME => 'SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4',
       PARAMETER_NAME  => 'AUTOPURGE',
       PARAMETER_VALUE => 'YES');
END;
/

以下示例删除隔离配置 SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4

BEGIN
    DBMS_SQLQ.DROP_QUARANTINE('SQL_QUARANTINE_3z0mwuq3aqsm8cfe7a0e4');
END;
/

查看隔离 SQL 语句执行计划的详细信息

可以查询 V$SQLGV$SQL 视图,以获取有关隔离 SQL 语句执行计划的详细信息。

V$SQLGV$SQL 视图的以下列显示 SQL 语句执行计划的隔离信息:

  • SQL_QUARANTINE:此列显示 SQL 语句执行计划的隔离配置的名称。
  • AVOIDED_EXECUTIONS:此列显示 SQL 语句的执行计划在被隔离后被阻止运行的次数。

将隔离配置从一个数据库传输到另一个数据库

可以使用 DBMS_SQLQ 包子程序—CREATE_STGTAB_QUARANTINECREATE_STGTAB_QUARANTINEUNPACK_STGTAB_QUARANTINE 将隔离配置从一个数据库转移到另一个数据库。

例如,您可能已经在 test 数据库上测试了隔离配置,并确认它们运行良好。然后可能需要将这些隔离配置加载到生产数据库中。

以下示例描述了使用 DBMS_SQLQ 包子程序将隔离配置从一个数据库*(源数据库)传输到另一个数据库(目标数据库)*的步骤:

  1. 使用 SQL*Plus,以具有管理权限的用户身份连接到源数据库,并使用 DBMS_SQLQ.CREATE_STGTAB_QUARANTINE 过程创建一个 staging 表。
    下面的示例创建了一个名为 TBL_STG_QUARANTINE 的 staging 表:

    BEGIN
      DBMS_SQLQ.CREATE_STGTAB_QUARANTINE (
        staging_table_name => 'TBL_STG_QUARANTINE');
    END;
    /
    
  2. 将隔离配置添加到要传输到目标数据库的 staging 表中。
    以下示例将名称以 QUARANTINE_CONFIG_ 开头的所有隔离配置添加到 staging表 TBL_STG_QUARANTINE 中:

    DECLARE
      quarantine_configs NUMBER;
    BEGIN
      quarantine_configs := DBMS_SQLQ.PACK_STGTAB_QUARANTINE(
                                staging_table_name => 'TBL_STG_QUARANTINE',
                                name => 'QUARANTINE_CONFIG_%');
    END;
    /
    

    DBMS_SQLQ.PACK_STGTAB_QUARANTINE 函数返回添加到 staging 表的隔离配置的数量。

  3. 使用 Oracle Data Pump Export 实用程序将登台表 TBL_STG_QUARANTINE 导出到转储文件中。

  4. 将转储文件从源数据库系统传输到目标数据库系统。

  5. 在目标数据库系统上,使用Oracle Data Pump Import 实用程序将 staging 表 TBL_STG_QUARANTINE 从转储文件导入到目标数据库。

  6. 使用 SQL*Plus,以具有管理权限的用户身份连接到目标数据库,并从导入的 staging 表创建隔离配置。
    以下示例基于导入的 staging 表 TBL_STG_QUARANTINE 中存储的所有隔离配置在目标数据库上创建隔离配置:

   DECLARE
     quarantine_configs NUMBER;
   BEGIN
     quarantine_configs := DBMS_SQLQ.UNPACK_STGTAB_QUARANTINE(
                               staging_table_name => 'TBL_STG_QUARANTINE');
   END;
   /

DBMS_SQLQ.UNPACK_STGTAB_QUARANTINE 函数返回在目标数据库中创建的隔离配置的数量。

示例:隔离消耗过多系统资源的 SQL 语句的执行计划

此示例展示了当 SQL 语句的执行计划超过使用资源管理器配置的资源消耗限制时,如何隔离该执行计划。

  1. 使用资源管理器,为用户 HR 执行的 SQL 语句指定 3 秒的执行时间限制。
    下面的代码通过使用 DBMS_RESOURCE_MANAGER 包子程序创建一个复杂的资源计划来执行这些操作:

    • 创建一个用户组 TEST_RUNAWAY_GROUP
    • 将用户 HR 分配给 TEST_RUNAWAY_GROUP 消费者组。
    • 创建一个资源计划 LIMIT_RESOURCE,当 SQL 语句超过 3 秒执行时间时终止。
    • LIMIT_RESOURCE 资源计划分配给 TEST_RUNAWAY_GROUP 消费者组。
    connect / as sysdba
    
    begin
    
      -- Create a pending area
      dbms_resource_manager.create_pending_area();
    
      -- Create a consumer group 'TEST_RUNAWAY_GROUP'
      dbms_resource_manager.create_consumer_group (
        consumer_group => 'TEST_RUNAWAY_GROUP',
        comment        => 'This consumer group limits execution time for SQL statements'
      );
    
      -- Map the sessions of the user 'HR' to the consumer group 'TEST_RUNAWAY_GROUP' 
      dbms_resource_manager.set_consumer_group_mapping(
        attribute      => DBMS_RESOURCE_MANAGER.ORACLE_USER,
        value          => 'HR',
        consumer_group => 'TEST_RUNAWAY_GROUP'
      );
    
      -- Create a resource plan 'LIMIT_RESOURCE'
      dbms_resource_manager.create_plan(
        plan    => 'LIMIT_RESOURCE',
        comment => 'Terminate SQL statements after exceeding total execution time'
      );
    
      -- Create a resource plan directive by assigning the 'LIMIT_RESOURCE' plan to 
      -- the 'TEST_RUNAWAY_GROUP' consumer group
      -- Specify the execution time limit of 3 seconds for SQL statements belonging to 
      -- the 'TEST_RUNAWAY_GROUP' group
      dbms_resource_manager.create_plan_directive(
        plan             => 'LIMIT_RESOURCE',
        group_or_subplan => 'TEST_RUNAWAY_GROUP',
        comment          => 'Terminate SQL statements when they exceed the' || 
                            'execution time of 3 seconds',
        switch_group     => 'CANCEL_SQL',
        switch_time      => 3,
        switch_estimate  => false
      );
    
      -- Allocate resources to the sessions not covered by the currently active plan 
      -- according to the OTHER_GROUPS directive
      dbms_resource_Manager.create_plan_directive(
        plan              => 'LIMIT_RESOURCE',
        group_or_subplan  => 'OTHER_GROUPS',
        comment           => 'Ignore'
      );
    
      -- Validate and submit the pending area
      dbms_resource_manager.validate_pending_area();
      dbms_resource_manager.submit_pending_area();
    
      -- Grant switch privilege to the 'HR' user to switch to the 'TEST_RUNAWAY_GROUP' 
      -- consumer group
      dbms_resource_manager_privs.grant_switch_consumer_group('HR',
                                                              'TEST_RUNAWAY_GROUP',
                                                              false);
      
      -- Set the initial consumer group of the 'HR' user to 'TEST_RUNAWAY_GROUP'
      dbms_resource_manager.set_initial_consumer_group('HR',
                                                       'TEST_RUNAWAY_GROUP');
    
    end;
    /
    
    -- Set the 'LIMIT_RESOURCE' plan as the top plan for the Resource Manager
    alter system set RESOURCE_MANAGER_PLAN = 'LIMIT_RESOURCE' scope = memory;
    
    -- Unlock the HR user and assign it the DBA role
    alter user hr identified by hr_user_password account unlock;
    grant dba to hr;
    
    -- Flush the shared pool
    alter system flush shared_pool;
    
  2. HR 用户连接 Oracle 数据库,执行超过 3 秒执行时间限制的 SQL 语句:

    select count(*) from employees emp1, employees emp2, employees emp3, employees emp4, employees emp5, employees emp6, employees emp7, employees emp8, employees emp9, employees emp10 where rownum <= 100000000;

    SQL 语句超过 3 秒的执行时间限制,被资源管理器终止,并显示如下错误信息:

    ORA-00040: active time limit exceeded - call aborted
    

    SQL 语句的执行计划现在被添加到隔离列表中,因此不允许它再次运行。

  3. 再次运行 SQL 语句。

    现在,SQL 语句应该立即终止,并显示以下错误消息,因为它的执行计划被隔离:

    ORA-56955: quarantined plan used
    
  4. 通过查询 v$sqldba_sql_quarantine 视图,查看 SQL 语句的隔离执行计划的详细信息。

    • 查询 v$sql 视图。v$sql 视图包含有关 SQL 语句的各种统计信息的信息,包括隔离统计信息。

      select sql_text, plan_hash_value, avoided_executions, sql_quarantine from v$sql where sql_quarantine is not null;

      该查询的输出类似于以下内容:

      SQL_TEXT                               PLAN_HASH_VALUE   AVOIDED_EXECUTIONS   SQL_QUARANTINE
      ------------------------------------   ---------------   ------------------   ------------------------------------
      select count(*)                        3719017987        1                    SQL_QUARANTINE_3uuhv1u5day0yf6ed7f0c
      from employees emp1, employees emp2, 
           employees emp3, employees emp4, 
           employees emp5, employees emp6,
           employees emp7, employees emp8, 
           employees emp9, employees emp10
      where rownum <= 100000000;
      

      sql_quarantine 列显示 SQL 语句执行计划的隔离配置自动生成的名称。

    • 查询 dba_sql_quarantine 视图。dba_sql_quarantine 视图包含有关 SQL 语句执行计划的隔离配置的信息。

      select sql_text, name, plan_hash_value, last_executed, enabled from dba_sql_quarantine;

      该查询的输出类似于以下内容:

      SQL_TEXT                               NAME                                   PLAN_HASH_VALUE   LAST_EXECUTED                  ENABLED
      ------------------------------------   ------------------------------------   ---------------   ----------------------------   -------
      select count(*)                        SQL_QUARANTINE_3uuhv1u5day0yf6ed7f0c   3719017987        14-JAN-19 02.19.01.000000 AM   YES
      from employees emp1, employees emp2, 
           employees emp3, employees emp4, 
           employees emp5, employees emp6,
           employees emp7, employees emp8, 
           employees emp9, employees emp10
      where rownum <= 100000000;
      

      name 列显示 SQL 语句执行计划的隔离配置自动生成的名称。

  5. 清理示例环境。

    下面的代码删除了为这个示例创建的所有数据库对象:

    connect / as sysdba
    
    begin
      for quarantineObj in (select name from dba_sql_quarantine) loop
        sys.dbms_sqlq.drop_quarantine(quarantineObj.name);
      end loop;
    end;
    /
    
    alter system set RESOURCE_MANAGER_PLAN = '' scope = memory;
    
    execute dbms_resource_manager.clear_pending_area();
    execute dbms_resource_manager.create_pending_area();
    execute dbms_resource_manager.delete_plan('LIMIT_RESOURCE');
    execute dbms_resource_manager.delete_consumer_group('TEST_RUNAWAY_GROUP');
    execute dbms_resource_manager.validate_pending_area();
    execute dbms_resource_manager.submit_pending_area();
    
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论