- 什么是Resource Manager
Oracle Database Resource Manager(RM)是Oracle用于管理负载冲突而设计的工具。RM在10g版本中已经诞生,但不完善,有很多Bug。在11g版本里已经相当成熟,我们也希望在平安的11g数据库推广。RM可以管理很多类型的负载冲突,就平安实践而言,我们主要管理CPU竞争。通过合理的设置,能将连接DB的所有session分组到若干消费组里面,为每个消费组设置最小保证CPU消耗百分比,当某个组里某个session出问题,导致CPU消耗100%的时候,RM会将影响局限在这个消费组内,其他消费组的session还是能够拿到之前设定的CPU使用量,正常运行,从而隔离CPU竞争带来的影响。 - RM工作机制简介
2.1 修改连接方式,设置消费组
我们在DB上创建service,所有应用连接都通过service连数据库
然后将service es_srv_oltp1 设置到消费组 cg_1 里面。如法炮制,将其他两个service也分别对应到cg_2和cg_3两个消费组里。
service 消费组
es_srv_oltp1 cg1
es_srv_etl cg2
es_srv_other cg3
不同的应用通过不同的service连接数据库,这样所有session都会对应到上述三个消费组里的一个。
2.2设置消费组的CPU保证值
CPU保证值是指当CPU使用率冲到100%(即出现争用)的时候,每个消费组获得的CPU配额。它不是限制值,是保证值。在出现争用的时候,RM的作用才体现出来(就像消防队,没火灾的时候,是感觉不到的,火灾来了,消防队才出现)。消费组CPU使用配额用百分比来表示,其总和是100%,设置如下:
service 消费组 CPU保证量
es_srv_oltp1 cg1 60%
es_srv_etl cg2 30%
es_srv_other cg3 10%
注:CPU总量,不是主机CPU总数,而是一个Oracle参数 cpu_count。即Oracle认为本库CPU使用量达到了cpu_count的设置值,即视为CPU出现争用,可能此时主机CPU使用率并未达到100%。同一主机上多个库的cpu_count设置及隔离,请参见第3节:3. What’s More? Instance Caging
2.3 情景演示
为了描述清楚,首先假设主机上只运行一个DB,DB独享整台主机的CPU(关于一台主机上多个DB的情况,有Resource Manager的兄弟 Instance Caging 技术处理,后面再详细介绍)。其次要引入“业务负载量”的概念,即衡量业务的实际CPU需求。例如某一时刻,cg1的业务负载量是45%,意思是负载独占这个库的所有资源运行,CPU消耗是45%。业务负载量也可能超过100%,例如cg1的业务负载量是300%,那么当前主机的CPU使用率肯定会冲到100%,换句话说,假设当前主机CPU增强为当前的3倍,那么刚好能够无等待地跑完这个负载量;如果主机CPU增强为当前的6倍,那么跑完这个负载量的CPU使用率是50%。(假设都是线性的)
场景1:通常情况
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 34% 34%
cg2 30% 22% 22%
cg3 10% 8% 8%
总计 100% 64% 64%
这种情况下,业务负载总和是没有超过CPU处理能力的,各消费组实际消耗量等于负载量。
场景2:某一消费组(cg2)业务负载量增大,超过了保证量,但总体CPU没有达到100%
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 34% 34%
cg2 30% 46% 46%
cg3 10% 8% 8%
总计 100% 88% 88%
虽然cg2负载量已经超过RM设置的保证值,但因为CPU没有出现争用,因此RM不会起作用,cg2可以使用超过其配额的CPU。
场景3:cg2业务负载量持续增大,整体CPU消耗超过100%
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 34% 34%
cg2 30% 88% 58%
cg3 10% 8% 8%
总计 100% 130% 100%
CPU已经100%,RM介入,一方面保证cg1与cg3的正常CPU使用,然后把剩下的所有CPU资源给cg2(但cg2仍然是不满足的,组内session争用CPU)
场景3.1:特别地,如果cg1和cg3的业务负载量回落,CPU能够“喂饱” cg2,那么争用可能消除(同场景2),RM不介入。
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 6% 6%
cg2 30% 88% 88%
cg3 10% 2% 2%
总计 100% 96% 96%
场景4,与场景3类似,但最重要的是,cg2的业务负载量远远超过了DB的处理能力,夸张一点,例如业务负载量为400%
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 34% 34%
cg2 30% 400% 58%
cg3 10% 8% 8%
总计 100% 442% 100%
那么RM介入,不管cg2负载量如何夸张,总能保证cg1和cg2的使用量不受影响(同场景3)。当然,这种情况下,无论cg1和cg2负载量如何回落,都有CPU争用。
场景4.1 cg1和cg2负载量回落之后的情况:
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 6% 6%
cg2 30% 400% 92%
cg3 10% 2% 2%
总计 100% 408% 100%
场景4.2 极端情况是,cg1和cg3业务负载量回落到0%,CPU依然100%,此时RM还是起效的:
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 0% 0%
cg2 30% 400% 100%
cg3 10% 0% 0%
总计 100% 400% 100%
场景4.3 如果这时候cg1或者cg3又有任务了,负载量又上来了,那么RM是会保证cg1或cg3正常需求的
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 23% 23%
cg2 30% 400% 77%
cg3 10% 0% 0%
总计 100% 423% 100%
场景5,当CPU 100%且两个消费组的业务负载量均超过目前可用CPU量,RM会按两者保证量的比例来分配剩余CPU:
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 120% 62%
cg2 30% 400% 31%
cg3 10% 7% 7%
总计 100% 527% 100%
cg1和cg2的业务负载量已经远远超过主机总量,他们按照2:1的比例,瓜分剩余的93%的CPU。而cg3是完全不受影响的(在保证值10%之内,需要多少就会用多少)
场景6, 极端情况,当每个消费组业务负载量均超过最小保证值,那么可以看到最终CPU消耗量与设置值相同了
消费组 CPU保证量 业务负载量 实际CPU消耗量
cg1 60% 120% 60%
cg2 30% 400% 30%
cg3 10% 50% 10%
总计 100% 570% 100%
2.4 有无RM的情况对比
如果没有RM,当CPU出现争用的时候,我们可以理解为,各个session之间CPU的实际消耗大致是按照其“申请量”也就是业务负载量的比例来分配的。
左图是有RM的场景4,右图是相同场景下没有RM的情况
消费组 CPU保证量 业务负载量 实际CPU消耗量 消费组 业务负载量 实际CPU消耗量
cg1 60% 34% 34% cg1 34% 7.69%
cg2 30% 400% 58% cg2 400% 90.50%
cg3 10% 8% 8% cg3 8% 1.81%
总计 100% 442% 100% 总计 442% 100%
可以看到,如果没有RM,cg1只能拿到7.69%的CPU资源,而其正常负载应该需要34%,因此cg1里的session会因为CPU不足出现大量等待,这就是我们平常看到的生产库某一个session将CPU耗完时,把其他session也堵塞的情况。而RM的核心作用,在于保证每一个消费组的最低消费量,而不至于被别人抢占。
2.5 其他
启用/禁用RM很简单,只需要设置一个Oracle的系统参数: alter system set resource_manager_plan = 'xxxx' scope=both;
设置之后立即生效,无需重启数据库。当然,启用/禁用之后,只对新的session有用,正在运行的语句不受影响。所以不能等到DB真的出现CPU争用才启用RM,必须事先就启用,防患于未然。
- What’s More? Instance Caging
RM只是隔离了一个DB内部的资源竞争,而一个主机上的多个DB,是通过Instance Caging(IC)来实现类似的作用的。步骤大致有两个: - 每个库都要启用RM
- 为每个库设置cpu_count参数,这就是该库能够消耗的CPU总量。这是个限制值,而非上述RM的保证值。当数据库CPU消耗达到cpu_count参数设置值时,Oracle即视作CPU出现争用,RM立即介入。注意,此时可能主机CPU消耗量还没有达到100%,但也可能早就100%了。
- 一个主机上可以有多个库,每个库都有独立的cpu_count设置。一般情况下,所有库的cpu_count之和,应该与主机真实cpu数相等(partitioned/瓜分)。当然,也可以“超分”(over-provisioning),即cpu_count数之和大于主机真实cpu数。此时,可能出现数据库cpu消耗量还没有达到cpu_count数,主机cpu使用率就已经冲到100%了,那么RM也是会介入的。这时候,各个库的cpu使用量,是按照cpu_count的比例来分配的。
注:cpu_count值可以动态在线调整,无需重启库。
场景分析:假设某主机逻辑CPU数一共是32个,上面运行了3个DB:
- 所有库都有启用IC ,设置为partitioned,即瓜分CPU
DB名 版本 cpu_count
DB-X 11g 10
DB-Y 11g 10
DB-Z 11g 12
总计 32
1.1 通常情况下(没有CPU争用):
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 7 7 7/32
DB-Y 11g 10 4 4 4/32
DB-Z 11g 12 8 8 8/32
1.2某一个DB负载异常,不会影响其余两个
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 7 7 7/32
DB-Y 11g 10 50 10 10/32
DB-Z 11g 12 8 8 8/32
1.3 某两个DB负载异常,也不会影响第三个
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 7 7 7/32
DB-Y 11g 10 50 10 10/32
DB-Z 11g 12 100 12 12/32
- IC设置为over-provisioning,所有库都有启用IC,并且超过主机总CPU数(50>32)
DB名 版本 cpu_count
DB-X 11g 10
DB-Y 11g 20
DB-Z 11g 20
总计 50
2.1 当整体负载偏小,每个实例都没有达到cpu_count上限,主机CPU也没有100%时,那么实际使用量是没有打折扣的。
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 7 7 7/32
DB-Y 11g 20 4 4 4/32
DB-Z 11g 20 8 8 8/32
2.2 当某一个库负载超过cpu_count,就算主机cpu还有剩余,也会打折
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 15 10 10/32
DB-Y 11g 20 4 4 4/32
DB-Z 11g 20 8 8 8/32
总计 50 27 22 22/32
2.3 也有可能每个库的CPU都没有达到cpu_count,但主机CPU使用率已经100%了(此时IC和RM是没有介入的)。此时每个库的CPU实际使用量是按照申请量的比例来分配的(暂且称为丛林法则),即谁负载高谁获得的多。
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 8 8/41*32=6.24 6.24/32=19.5%
DB-Y 11g 20 18 18/41*32=14.05 14.05/32=43.9%
DB-Z 11g 20 15 15/41*32=11.71 11.71/32=36.6%
总计 50 41 32.00 100.0%
2.4 如果DB-Z的CPU消耗持续增长,超过cpu_count时,IC/RM介入,将其实际申请量限制在20。因此,三者是以8:18:20的比例来瓜分CPU的。
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 8 8/46*32=5.57 17.4%
DB-Y 11g 20 18 18/46*32=12.52 39.1%
DB-Z 11g 20 40 20/46*32=13.91 43.5%
总计 50 66 32.00 100.0%
业务负载量看起来是66,但实际只有46。
2.5 以2.4为基础,进一步看RM行为。DB-Y上由于IC/RM没有介入,因此各CG实际CPU使用量按照“丛林法则”分配:
DB名 消费组 CPU分配% RM保证量 业务负载量 实际使用量
DB-Y CG1 20% 2020%=4 15 12.52(15/18)=10.43
CG2 80% 20*80%=16 3 12.52*(3/18)=2.087
可以看到,虽然CG2的CPU保证量是16,但由于没有触发RM生效,就算其申请量很少,只有3个CPU,也无法满足(实际只拿到2..087个)。这个例子说明,超分的IC设置,会导致RM效果打折扣。
- 存在非11g库,不是所有库都能启用IC,但cpu_count没有超分。即便是这样,11g的库也会受非11g库影响(丛林法则)
DB名 版本 cpu_count
DB-X 11g 10
DB-Y 11g 8
DB-Z 10g 14
总计 32
DB名 版本 cpu_count 业务负载量
(CPU申请量) CPU实际使用量 实际使用率
DB-X 11g 10 6 6/50*32=3.84 12.0%
DB-Y 11g 8 4 4/50*32=2.56 8.0%
DB-Z 10g 14 40 40/50*32=25.6 80.0%
总计 32 50 32 100.0%
- 说明
本文描述生产库实施Resource Manager 的详细脚本。
。
- 详细步骤
2.1 设置cpu_count
cpu_count可以在线调整,无需重启库
alter system set cpu_count=32 scope=both;
注意:按照平安规范,另一个重要参数log_buffer会受cpu_count影响,请一并考虑。
2.2 service管理
2.2.1 service创建
有两种创建Service的方式:
- 直接修改初始化参数 service_names
首先检查原service_names参数:
SQL> show parameter service_names
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
service_names string srvp_x1, srvp_x2
如果要新增一个叫srvp_x3的service,直接将其加在参数后面,注意多值参数必须用逗号分隔
alter system set service_names='srvp_x1','srvp_x2','srvp_x3' scope=both;
执行之后,在数据库里添加了service的同时(从dba_services查询),这个service也自动启动了(从v$active_services)。也就是说如果DB重启,这三个service都会自动启动。
- 使用dbms_service.create_service 包创建service,分为两步:
第一步仅仅创建service,但不启动(仅仅从dba_services能够查到,但v$active_services和v$parameter里没有,监听里也没有)
exec dbms_service.create_service('srvp_x3', 'srvp_x3');
第二步启动service
exec dbms_service.start_service ('srvp_x3');
这样service才算真正可用。
技术上也可以用直接修改参数service_names的方式来创建,但我们不允许这样做。因为DG结合service实现透明故障切换的话,所有service必须使用dbms包创建(不是每个库都要启动所有service,是选择性启动的。有DB startup trigger负责按条件拉起service)。详见DG规范。
2.2.2 service校验
1、 使用动态监听,以便使service立即生效 (local_listener参数设置正确)
2、 lsnrctl里查看service状态
注:默认情况下,监听里的service都带上了db_domain的后缀。我们的规范要求设置db_domain为空,这样监听里的service与设置的值就一样了。
2.2.3 service删除
exec dbms_service.stop_service ('srvp_x3');
exec dbms_service.delete_service ('srvp_x3');
2.2.4 使用service连接数据库
JDBC连接写法:jdbc:oracle:thin:@(description =(address = (protocol = tcp)(host = xxXXXXX)(port = 1534))(connect_data = (service_name = srvp_x3)))
tns_names连接写法: x3=(description =(address = (protocol = tcp)(host = xxXXXXX)(port = 1534))(connect_data = (service_name = srvp_x3)))
如果要实现TAF,连接串写法详见相关规范。
2.3 Resource Manager对象管理
使用dbms_resource_manager来管理RM对象。创建消费组以及设置配额等操作,需要整体生效,不能有中间状态。因此在正式脚本开头,需要先清空并创建一个未决区(pending area),在脚本结束需校验并提交,格式如下:
begin dbms_resource_manager.clear_pending_area(); end; --清空
begin dbms_resource_manager.create_pending_area(); end; --新建
具体脚本
begin dbms_resource_manager.validate_pending_area();end; --校验
begin dbms_resource_manager.submit_pending_area();end; --提交
clear_pending_area 的作用,是清除当前未决区,以防止之前有命令未生效,干扰本次操作。
2.3.1 全新创建Resource Manager Plan
Resource Manager作为新建库的标配,只要是新建库,都应该创建并实施RM。本节讲述首次创建Resource Manager。
begin dbms_resource_manager.clear_pending_area(); end; --清空
begin dbms_resource_manager.create_pending_area(); end; --新建
2.3.1.1 创建资源计划:
BEGIN
DBMS_RESOURCE_MANAGER.CREATE_PLAN(
PLAN => 'SALES_NORMAL',
COMMENT => 'Normal plan for sales');
END;
注意,对于一个库,可以创建多个资源计划并可以随时切换。但目前我们只创建一个,命名方式是{sid}_NORMAL
2.3.1.2 创建消费组:
begin
dbms_resource_manager.create_consumer_group (
consumer_group => 'cg_sales_pub_life',
comment => 'for PSS-ESALES-LIFE and PSS-ESALES-PUB');
end;
重复上述命令,逐个创建消费组
2.3.1.3 设置资源配额
begin
dbms_resource_manager.create_plan_directive(
plan => 'SALES_NORMAL',
group_or_subplan => 'cg_sales_pub_life',
mgmt_p1 => 75,
comment => 'CPU 75%'
);
end;
资源计划指示即设置每个消费组的CPU保证值。如法炮制,为每个消费组指定该值。注意,最后必须为OTHER_GROUPS指定保证值:
begin
dbms_resource_manager.create_plan_directive(
plan => 'SALES_NORMAL',
group_or_subplan => 'OTHER_GROUPS',
comment => 'Directives for the other users group...',
mgmt_p1 => 10
);
end;
2.3.1.4 创建映射关系
即为每一个service指定对应的消费组
begin
dbms_resource_manager.set_consumer_group_mapping
(attribute =>'service_name',
value => 'srv_sales_pss-pub-life',
consumer_group => 'cg_sales_pub_life');
end;
重复上述语句,为每个service设置映射关系。如果没有设置映射关系,则自动对应到OTHER_GROUPS里。
注:RM提供了多种方式设置映射关系,例如根据连接用户,或者客户端程序等。我们目前只用service映射到消费组。但是针对cg_admin,使用用户映射,将sys和dbmgr映射到cg_admin(以下代码不用改动):
begin
dbms_resource_manager.set_consumer_group_mapping
(attribute =>'oracle_user',
value => 'sys',
consumer_group => 'CG_ADMIN');
end;
begin
dbms_resource_manager.set_consumer_group_mapping
(attribute =>'oracle_user',
value => 'dbmgr',
consumer_group => 'CG_ADMIN');
end;
--将oracle_user的优先级提到service_name之前:
begin dbms_resource_manager.set_consumer_group_mapping_pri
( explicit =>1,
oracle_user =>2,
service_name =>3,
client_os_user =>4,
client_program =>5,
client_machine =>6,
module_name =>7,
module_name_action =>8,
service_module =>9,
service_module_action =>10,
client_id => 11);
end;
至此,RM对象创建完毕,检查提交:
begin dbms_resource_manager.validate_pending_area();end;
begin dbms_resource_manager.submit_pending_area();end;
2.3.1.5 授权
针对不同数据库用户,每个消费组都有权限控制,即不是所有用户的session都可以映射到该消费组的,必须显示授权。如果不想每个用户都授权,可以将权限授予PUBLIC用户,这也是平安目前的做法。
begin dbms_resource_manager.clear_pending_area(); end;
begin dbms_resource_manager.create_pending_area(); end;
begin
dbms_resource_manager_privs.grant_switch_consumer_group(
grantee_name => 'public',
consumer_group => 'cg_sales_pub_life',
grant_option => FALSE);
end;
也就是说允许所有用户的session都可以映射到cg_sales_pub_life(前提是session使用了对应的service连接数据库)。
重复上述语句,将每个消费组授权给PUBLIC用户。
校验并提交
begin dbms_resource_manager.validate_pending_area();end;
begin dbms_resource_manager.submit_pending_area();end;
2.3.2 在已有Resource Manager Plan里新增消费组
一个已经应用RM的库上,新增子系统,需要新增消费组。此时需要调整其他消费组的配额,然后创建新的消费组。
begin dbms_resource_manager.clear_pending_area(); end;
begin dbms_resource_manager.create_pending_area(); end;
调整消费组配额
begin dbms_resource_manager.update_plan_directive(
plan => 'SALES_NORMAL',
group_or_subplan => 'cg_sales_pub_life',
new_mgmt_p1 => 70,
new_comment => 'CPU 70%');
end;
新增消费组跟前面一致,略过。
提交
begin dbms_resource_manager.validate_pending_area();end;
begin dbms_resource_manager.submit_pending_area();end;
更多方法,请参阅Oracle文档。
完整脚本请参见《RM演示脚本.sql》。
虽然RM相关组件设置语句繁多,但内容格式较为固定,可以使用excel生成脚本。参见《RM脚本模板.xlsx》。
2.3.3 应用资源计划
通过设置参数resource_manager_plan来应用RM,立即生效无需重新启库。当然,立即生效并不意味着RM立即介入。介入条件参见2.1.2描述。
alter system set resource_manager_plan = 'SALES_NORMAL' scope=both;
相似地,停用资源计划,只要将该参数置空即可。
2.4 校验检查
2.4.1 检查相关参数:
select vp.name, vp.display_value, vp.isdefault, vp.isses_modifiable, vp.issys_modifiable
from v$parameter vp
where vp.name in ('service_names','local_listener','parallel_max_servers','parallel_servers_target'
,'parallel_degree_policy','resource_manager_plan','cpu_count'
,'parallel_adaptive_multi_user'
,'parallel_degree_limit');
2.4.2 查看消费组映射关系和cpu设置值
select * from dba_rsrc_group_mappings rm
select * from dba_rsrc_plan_directives rd where rd.plan = 'SALES_NORMAL';
2.4.3 查看连接session 的分布
select vs.resource_consumer_group , count(1)
from v$session vs
group by vs.resource_consumer_group
带service与CG:
select vs.service_name, vs.resource_consumer_group ,count(1)
from v$session vs
group by vs.service_name, vs.resource_consumer_group
2.5 RAC环境处理
RAC环境RM设置跟单节点完全一致,只在一个节点创建即可。
2.6 性能问题调查
当主机CPU冲高,RM介入后,可以用下面方法详细调查。注意请首先备份v$rsrcmgrmetric_history, v$active_session_history 两个重要视图!否则刷出内存了就不好调查问题了。
查看消费组实时的CPU使用情况和丢弃情况:
select begin_time, rh.consumer_group_name,
(select value from v$osstat where stat_name = 'NUM_CPUS') num_cpus,
(select value from v$parameter where name = 'cpu_count') num_db_cpus,
round(sum(cpu_consumed_time) / 60000,3) avg_running,
round(sum(cpu_wait_time) / 60000,3) avg_throttled
from v$rsrcmgrmetric_history rh
group by begin_time , rh.consumer_group_name order by begin_time desc , consumer_group_name ;
上述视图是1分钟的汇总量,可能将波峰削掉,从而看不出问题。可以从ASH统计每1秒的精确数据(gmact_ash_20180730为保存的ash):
select ash.sample_time, cg.consumer_group , round(sum(cnt)/60*100,2)||'%' act_util, rd.cpu_p1||'%' plan_util
from (
select ga.sample_time, ga.consumer_group_id, sum(1) cnt
from gmact_ash_20180730 ga
where sample_time > to_date('2018/07/30 09:40:07','yyyy/mm/dd hh24:mi:ss')
and sample_time<= to_date('2018/07/30 09:41:07','yyyy/mm/dd hh24:mi:ss')
and ga.session_state = 'ON CPU'
group by ga.sample_time ,ga.consumer_group_id
) ash ,dba_rsrc_consumer_groups cg ,dba_rsrc_plan_directives rd
where cg.consumer_group_id = nvl(ash.consumer_group_id, select consumer_group_id from dba_rsrc_consumer_groups where consumer_group = 'OTHER_GROUPS')
and rd.group_or_subplan = cg.consumer_group
and rd.plan = 'RP_GMACT_NORMAL'
group by ash.sample_time, cg.consumer_group ,rd.cpu_p1
order by ash.sample_time, cg.consumer_group
从AWR历史视图,查看每个snapid的使用情况。这是15分钟的平均量,粒度就更粗了:
select begin_time, end_time, gap_sec, snap_id, cg_name , cpu_time_ms ,cpu_wait_ms
, round(cpu_time_ms/1000/gap_sec,3) cpu_consumed
, round(cpu_wait_ms/1000/gap_sec,3) cpu_throttled
from (
select s.begin_time, s.end_time, rc.snap_id, rc.consumer_group_name cg_name ,rc.consumed_cpu_time ,rc.cpu_wait_time
, rc.consumed_cpu_time - lag(rc.consumed_cpu_time,1,rc.consumed_cpu_time) over (order by rc.consumer_group_name, rc.snap_id) cpu_time_ms
, rc.cpu_wait_time - lag(rc.cpu_wait_time,1,rc.cpu_wait_time) over (order by rc.consumer_group_name, rc.snap_id) cpu_wait_ms
, min(rc.snap_id) over (partition by 1) pre_snap
, extract(minute from gap)*60 + extract(second from gap) as gap_sec
from dba_hist_rsrc_consumer_group rc
,(
select ss.snap_id, ss.begin_interval_time begin_time, ss.end_interval_time end_time, (ss.end_interval_time-ss.begin_interval_time) gap
from dba_hist_snapshot ss
where ss.begin_interval_time > to_date('20180928 05:40','yyyymmdd hh24:mi')
and ss.begin_interval_time < to_date('20180928 06:20','yyyymmdd hh24:mi')
)s
where rc.snap_id = s.snap_id
order by rc.consumer_group_name, rc.snap_id
)
where snap_id != pre_snap
order by snap_id , cg_name