因业务需要,数据库中有一张表每时每刻都有数据插入,数据量比较庞大,都是些物联网数据。最近一段时间,发现在工作日周一至周五晚上10点多,和周六周日早上6点多发生数据插入失败的情况,经日志记录,在insert那张表时Oracle数据库报错:ORA-01013: 用户请求取消当前的操作。
一开始是怀疑自己的ORM框架存在问题,由于我用的是C#语言,采用了SqlSugar作为ORM框架。后替换为Oracle原生框架也存在insert失败或一直等待的情况,所以排除了ORM框架问题。
不管用事务方式批量插入数据还是直接SQL语句单条插入,均存在ORA-01013问题。
在问题发生时刻,在另一台计算机上执行同样的SQL语句一样报错。
经测试,问题发生时,仅对那张大数据表的插入产生了报错,而别的表的插入查询均未出现问题。初步判定为那张表被锁。在数据库服务器上翻阅trace日志,发现问题产生时刻存在如下trc文件记录:
*** 2023-09-23 06:36:58.786
*** SESSION ID:(6333.24337) 2023-09-23 06:36:58.786
*** CLIENT ID:() 2023-09-23 06:36:58.786
*** SERVICE NAME:(SYS$USERS) 2023-09-23 06:36:58.786
*** MODULE NAME:(DBMS_SCHEDULER) 2023-09-23 06:36:58.786
*** ACTION NAME:(ORA$AT_OS_OPT_SY_19107) 2023-09-23 06:36:58.786
ORA-04021: timeout occurred while waiting to lock object
*** 2023-09-23 06:36:58.786
DBMS_STATS: GATHER_STATS_JOB: GATHER_TABLE_STATS('"XXX"','"XXXX"','""', ...)
DBMS_STATS: ORA-04021: timeout occurred while waiting to lock object
*** 2023-09-23 06:52:13.068
DBMS_STATS: GATHER_STATS_JOB: GATHER_TABLE_STATS('"XXX"','"XXXXX"','"XXXX"', ...)
DBMS_STATS: ORA-04021: timeout occurred while waiting to lock object
*** 2023-09-23 07:07:30.528
DBMS_STATS: GATHER_STATS_JOB: GATHER_TABLE_STATS('"XXX"','"XXXXX"','"XXXX"', ...)
DBMS_STATS: ORA-04021: timeout occurred while waiting to lock object
再登录数据库SYS账号,查询发生问题时刻执行的SQL语句,找到了:
SELECT SUM(x) FROM (SELECT CASE WHEN B != LAG(B) OVER (ORDER BY "XXX") THEN 1 ELSE 0 END x FROM (SELECT "XXX", DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) b FROM "XX"."XXXX" WHERE ROWNUM < 1000))
正是需要插入的那张表,执行者为SYS,所以排除业务数据库XXX的定时任务等操作。
由于时间发生比较特殊,为工作日晚10点多和周末早6点多,顺着这个思路继续探索。
查询SYS的计划任务:
select window_name,repeat_interval,duration,enabled from dba_scheduler_windows;
结果:
发现了工作日和周末的执行时间。那执行的是什么,经过度娘的帮助,发现是Oracle的自动任务可能会产生ORA-04021: timeout occurred while waiting to lock object 问题。
查询自动维护任务:
select client_name,status from dba_autotask_client;
有三个任务:auto optimizer stats collection、auto space advisor、sql tuning advisor。其中第三个好像是SQL优化建议的,尝试把第三个任务关闭:
--关闭sql tuning advisor
BEGIN
DBMS_AUTO_TASK_ADMIN.disable(
client_name => 'sql tuning advisor',
operation => NULL,
window_name => NULL);
END;
至此,问题解决!!!