本文节选自《云和恩墨技术通讯》(12月刊)
下载链接:https://www.modb.pro/doc/1593

enq:HW-contention等待事件争用主要发生在数据插入、修改或手工对该对象allocate/deallocate空间时,为防止多个进程同时修改HWM而提供的锁叫做HW锁,想要移动HWM的进程必须获取HW锁。
若在获取HW锁过程中发生争用,则等待enq:HW-contention 事件。在并发量过高的情况下,有可能引发严重的数据库性能问题。在此,我们通过一个故障实例来描述风险发生的具体场景。
问题描述
某客户生产系统多个核心库发生告警,业务反馈对前台影响严重。查看故障期间的等待事件信息,发现当时主要的等待事件为enq: HW - contention等待。

问题分析
进一步查看故障期间的TOP SQL信息,发现对应的SQL主要是SQL_ID dugcxypa8u957。

对应SQL是往T_XXX表中插入数据。观察该表的DDL语句得知是T_XXX表按照天进行interval分区。

采样故障期间三分钟的ASH数据进行分析:

SQL> select DBMS_UTILITY.data_block_address_file(to_number(3841531793)) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(TO_NUMBER(3841531793))
-----------------------------------------------------------
915
SQL> select DBMS_UTILITY.data_block_address_block(to_number(3841531793)) from dual;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(TO_NUMBER(3841531793))
------------------------------------------------------------
3743633




根据等待事件enq:HW-contention参数p2、p3可以查出发生enq:HW-contention等待事件的对象是T_XXX表的分区SYS_Pxxx的extent_id 0对象上,也就是在新创建每天的分区SYS_Pxxx分配extent_id 0的初始段大小和HW后,随着数据的插入导致需要申请更多的空间来移动高水位,从而并发插入数据就会出现enq:HW-contention等待。
造成HW竞争的根本原因为数据段的High Water Mark高水位线移动时,每次移动都要获取独占锁。在大并发的insert 环境下最容易出现该问题。
问题解决
对于此类情况,可以考虑以下几种处理方式:
1)手工推进高水位线,此方法比较安全。提前预估每天的数据量,在分区创建的同时直接手工给足够,这样的好处是不会再去持有HW锁了因为高水位线已经足够高了,坏处就是该操作为DDL 操作,OGG 与logical standby 需要处理下,另外也可能会浪费一定空间。
2)采取hash分区方式对数据表进行打散,可以对T_XXX表按照ID字段进行hash分区,分区数量建议采用8或者16即可,Hash分区对于数据插入时不用担心热点数据导致某个数据表或者索引出现空间不足而需要重新申请空间。
目前数据表采用的是range时间字段的分区,对于每天插入数据新生成分区,新增分区依然会存在热点数据,并发环境对于热点数据极容易出现enq索引分裂、ITL事务槽、HW高水位线等竞争。




