适用版本
OceanBase 数据库 V2.x、V3.x 版本。
问题描述
在业务更新数据量没有较大增长的情况下,发现 CLOG 文件快速增长。
问题原因
通过系统视图 gv$sesstat 分析 session 的统计信息,发现有 session 产生了大量的 CLOG 日志。
obclient> select s.con_id,s.sid,s.svr_ip,n.STAT_ID,n.`STATISTIC#`,n.name,s.value
from gv$sesstat s,v$statname n
where s.con_id=n.con_id
and s.`STATISTIC#`=n.`STATISTIC#`
and n.name='clog trans log total size'
order by s.value desc
limit 10;
返回结果如下。
+--------+------------+---------------+---------+------------+---------------------------+-------+
| con_id | sid | svr_ip | STAT_ID | STATISTIC# | name | value |
+--------+------------+---------------+---------+------------+---------------------------+-------+
| 1006 | 3221729966 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 53920 |
| 1006 | 3221707597 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 8101 |
| 1006 | 3221707308 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 7795 |
| 1006 | 3221707579 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 6480 |
| 1006 | 3221541930 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 6044 |
| 1006 | 3221715982 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 6043 |
| 1006 | 3221715763 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 5168 |
| 1006 | 3221707688 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 5168 |
| 1006 | 3221707512 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 5019 |
| 1006 | 3221633486 | 11.xxx.xx.xxx | 80057 | 381 | clog trans log total size | 4439 |
+--------+------------+---------------+---------+------------+---------------------------+-------+
从 gv$sql_audit 或者 __all_virtual_processlist 中查看 session 中执行的 DML,定位到以下 SQL。
obclient> UPDATE T1
SET SERVER_IP = '192.xxx.x.xx',
IS_DOING = 'n',
STATUS = 'S',
RETRY_TIMES = 0,
FAIL_REASON = NULL,
UPDATED_AT=SYSDATE,
UPDATED_BY='SYSTEM'
WHERE ID = 252330831
AND CREATED_AT >= TRUNC(SYSDATE - 1)
T1 表是一个按日分区的表,CREATED_AT 为分区键。该语句实际只更新几条记录,且记录长度有限,但是却产生了大量的 CLOG。经过访问路径的分析,发现该语句因为没有准确限定分区的范围,会产生一个涉及 300+ 分区的分布式事务,其中大部分分区上并没有实际更新的记录。在 OceanBase 数据库中,分布式事务的每一个参与者都要记录参与者的列表信息。因此,该语句虽然只需要很小的 clog 来记录 redo 日志,但却需要大量的 clog 来记录参与者信息,clog 的日志量放大了近万倍。 clog 日志的长度的计算公式为:扫描分区数 * (update 日志量 + PK数量 * 20 字节)。
解决方法
修改 SQL 来增加分区边界的限制,把 300+ 分区的更新操作变为单个分区。
obclient> UPDATE T1
SET SERVER_IP = '192.xxx.x.xx',
IS_DOING = 'n',
STATUS = 'S',
RETRY_TIMES = 0,
FAIL_REASON = NULL,
UPDATED_AT=SYSDATE,
UPDATED_BY='SYSTEM'
WHERE ID = 252330831
AND CREATED_AT >= TRUNC(SYSDATE - 1)
AND CREATED_AT < TRUNC(SYSDATE)