暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

Oracle SQL隔离详解

原创 文盲筱烨 2021-11-25
3110

Oracle SQL Quarantine – by Firsouler

Oracle 19c开始,我们可以使用SQL隔离,来隔离语句的执行计划,如果使用了SQL隔离,消耗资源或时间超过阈值的,则不允许执行,从而防止数据库整体性能下降。

通过DBMS package进行设定,主要步骤如下:

  • 1.创建资源计划
  • 2.创建SQL隔离策略:可以根据已知的SQL_ID或者SQL_TEXT来创建。
  • 3.修改SQL隔离参数:如cpu_time
  • 4.查看隔离的详细配置(DBA_SQL_QUARANTINE)
  • 5.查看隔离SQL的详细语句(v$sql)
  • 5.启动和关闭SQL隔离策略:SQL隔离策略在创建之后,默认情况下是直接被启用的。

DBMS_SQLQ说明

DBMS_SQLQ程序

Procedure Description
ALTER_QUARANTINE Procedure 在隔离配置中为SQL语句的执行计划指定隔离阈值
CREATE_QUARANTINE_BY_SQL_ID Function 使用SQL ID为SQL语句的执行计划创建隔离配置
CREATE_QUARANTINE_BY_SQL_TEXT Function 使用SQL语句为SQL语句的执行计划创建隔离配置
CREATE_STGTAB_QUARANTINE Procedure 创建临时表存储隔离配置
DROP_QUARANTINE Procedure 删除隔离配置
GET_PARAM_VALUE_QUARANTINE Function 查看在隔离配置中指定的隔离阈值的值
PACK_STGTAB_QUARANTINE Function 将一个或多个隔离配置添加到存储表
UNPACK_STGTAB_QUARANTINE Function 根据存储表在数据库中创建隔离配置

ALTER_QUARANTINE

语法:

DBMS_SQLQ.ALTER_QUARANTINE ( quarantine_name IN VARCHAR2, parameter_name IN VARCHAR2, parameter_value IN VARCHAR2);
参数 说明
quarantine_name 隔离配置的名字
parameter_name 需要为其指定隔离阈值的资源名称。 可以指定以下任一值
•CPU_TIME:CPU时间
•ELAPSED_TIME:消耗时间
•IO_MEGABYTES:以兆字节为单位的I/O
•IO_REQUESTS:物理I/O请求数
•IO_LOGICAL:逻辑I/O请求数
•ENABLED:标记以启用或禁用隔离配置,默认值为是。
•AUTOPURGE:标记以启用或禁用隔离配置的自动清除.如果设置为’是’,则在53周后(如果未使用)会自动清除隔离配置。如果将其设置为NO,则不会清除隔离配置。 默认值为是.
parameter_value 指定的资源的隔离阈值

举例:

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; /

CREATE_QUARANTINE_BY_SQL_ID 函数

参考:

--语法 DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_ID ( sql_id IN VARCHAR2, plan_hash_value IN NUMBER DEFAULT NULL) RETURN VARCHAR2; --例子 DECLARE quarantine_config VARCHAR2(30); BEGIN quarantine_config := DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_ID(SQL_ID => '8vu7s907prbgr'); END; / --or hash_value DECLARE quarantine_config VARCHAR2(30); BEGIN quarantine_config := DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_ID(SQL_ID => '8vu7s907prbgr', PLAN_HASH_VALUE => '3488063716'); END; /

CREATE_QUARANTINE_BY_SQL_TEXT 函数

参考:

--语法 DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_TEXT ( sql_text IN CLOB, plan_hash_value IN NUMBER DEFAULT NULL) RETURN VARCHAR2; --例子,也可以增加hash_value 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_TEXT 函数

参考:

--语法 DBMS_SQLQ.CREATE_STGTAB_QUARANTINE ( staging_table_name IN VARCHAR2, staging_table_owner IN VARCHAR2 DEFAULT NULL, tablespace_name IN VARCHAR2 DEFAULT NULL); --例子,创建一个存储表TBL_STG_QUARANTINE。并将其表所有者设置为执行此过程的数据库用户 BEGIN DBMS_SQLQ.CREATE_STGTAB_QUARANTINE(STAGING_TABLE_NAME => 'TBL_STG_QUARANTINE'); END; /

DROP_QUARANTINE程序

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

GET_PARAM_VALUE_QUARANTINE

--quarantine_name 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; /

PACK_STGTAB_QUARANTINE

--语法 DBMS_SQLQ.PACK_STGTAB_QUARANTINE ( staging_table_name IN VARCHAR2, staging_table_owner IN VARCHAR2 DEFAULT NULL, name IN VARCHAR2 DEFAULT '%', sql_text IN VARCHAR2 DEFAULT '%', enabled IN VARCHAR2 DEFAULT NULL) RETURN NUMBER; --eg DECLARE quarantine_configs NUMBER; BEGIN quarantine_configs := DBMS_SQLQ.PACK_STGTAB_QUARANTINE( STAGING_TABLE_NAME => 'TBL_STG_QUARANTINE', NAME => 'SQL_QUARANTINE_%'); END; /

举例

测试环境:

SQL> select banner_full from v$version; BANNER_FULL -------------------------------------------------------------------------------- Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.6.0.0.0

1.创建资源隔离(自动sql隔离)

注意,该特性只能在Exadata上使用,模拟该特性,需要通过设置参数来实现

alter system set “_exadata_feature_on”=true scope=spfile;

--1.创建组TEST_RUNAWAY_GROUP --2.用户HR指定到组TEST_RUNAWAY_GROUP --3.创建一个资源计划LIMIT_RESOURCE --4.将LIMIT_RESOURCE指定到组TEST_RUNAWAY_GROUP 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 ); --llocate 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 oracle account unlock; grant dba to hr; --Flush the shared pool alter system flush shared_pool; --查看资源管理计划 set lines 200 pages 999 col plan for a20 col status for a10 col comments for a60 col GROUP_OR_SUBPLAN for a18 select plan,type,GROUP_OR_SUBPLAN,switch_time,MAX_EST_EXEC_TIME,status,comments from DBA_RSRC_PLAN_DIRECTIVES where plan='LIMIT_RESOURCE'; --删除资源隔离 删除资源隔离计划 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();

2.执行相关SQL

第一次执行,首先使用资源管理中限制,第二次会自动使用sql隔离相关限制

set timing on select count(*) from hr.employees emp1, hr.employees emp2,hr.employees emp3, hr.employees emp4, hr.employees emp5, hr.employees emp6, hr.employees emp7, hr.employees emp8,hr.employees emp9, hr.employees emp10 where rownum <= 100000000; --报错示例 ERROR at line 1: ORA-00040: active time limit exceeded - call aborted --or ORA-56955: quarantined plan used

3.手动创建资源隔离

set lines 200 col sql_text for a60 col SQL_QUARANTINE for a20 select sql_text,sql_id, plan_hash_value, avoided_executions, sql_quarantine from v$sql where sql_text like '%employees%'; --添加sql declare quarantine_config varchar2(30); begin quarantine_config := DBMS_SQLQ.CREATE_QUARANTINE_BY_SQL_TEXT(sql_text => to_clob('&sql_text')); end; / --检查设置 set lines 200 pages 999 col name for a30 col sql_text for a60 col elapsed_time for a10 col cpu_time for a10 col LAST_EXECUTED for a10 select name,sql_text,elapsed_time,cpu_time,last_executed,enabled from dba_sql_quarantine; --设置超时3秒 begin DBMS_SQLQ.ALTER_QUARANTINE( QUARANTINE_NAME => '', PARAMETER_NAME =>'ELAPSED_TIME', PARAMETER_VALUE =>'5'); END; / begin DBMS_SQLQ.ALTER_QUARANTINE( QUARANTINE_NAME => '', PARAMETER_NAME =>'CPU_TIME', PARAMETER_VALUE =>'5'); END; / --删除 BEGIN DBMS_SQLQ.DROP_QUARANTINE('SQL_QUARANTINE_355nsmzubt1r4'); END; /

参考

  • https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/DBMS_SQLQ.html#GUID-C07258CB-4706-4722-AE5B-85184173B70B
  • https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/diagnosing-and-resolving-problems.html#GUID-9B3EC88E-E330-4B7E-BF98-617803A24092
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论