1

作为 ETL 过程的一部分,我有这个交换子分区声明:

ALTER TABLE DWH.QV_FACT_AMS EXCHANGE SUBPARTITION P08_2018_300_SALES WITH TABLE DWH.STG_QV_FACT_AMS;

(每个运行不同的子分区但相同的 2 个表)。

我们开始得到一个异常:

ORA-00054: 资源繁忙并使用指定的 NOWAIT 获取或超时已过期。

这意味着某些进程会更新表,我们无法更改。

由于最终表 - QV_FACT_AMS 仅用于报告,而 STG_QV_FACT_AMS 是在 ETL 本身中创建的内部动态表,我不知道谁可以更新这些表。

ETL 不能与 ETL 本身的另一次运行发生冲突,因此不能尝试从这两个进程修改同一个表。

交换语句每天运行很多次并正常完成,异常仅在晚上 9 点左右引发。

所以我在这两张表上应用了 AUDIT ALL:

AUDIT ALL on dwh.qv_Fact_ams;
AUDIT ALL on dwh.stg_qv_Fact_ams;

但是对表格的所有访问都不是在那个时间段内,只有 select 不应该锁定表格。

失败日志示例:

LOG_ID: 5879089
START_TIME: 18-07-2019 21:29:01
END_TIME: 18-07-2019 21:29:28
STATUS: FAILED
ORA_EXCEPTION: ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

我们可以看到异常发生在 18-07-2019 21:29:28。

这是审计:

SELECT  * 
FROM DBA_MAINT.AUD$ 
WHERE OBJ$NAME IN ('QV_FACT_AMS','STG_QV_FACT_AMS') 
ORDER BY TIMESTAMP# DESC;

除了 etl 本身,唯一的访问是只有 action# = 3(选择),3 小时后......

4

1 回答 1

0

在会话级别设置 DDL_LOCK_TIMEOUT 以找出谁在阻止命令。

使用默认设置,锁定表上的 DDL 将立即失败:

--Session #1: Insert but do not commit:
create table table1(a number);
insert into table1 values(1);

--Session #2:
--ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
alter table table1 move;

相反,我们可以告诉 Oracle 等待一定的秒数,而不是立即失败。

--Session #2:
--The second command will hang for 9999 seconds, or until the lock is free.
alter session set ddl_lock_timeout = 9999;
alter table table1 move;

这给了我们足够的时间来调查是什么会话和语句阻塞了我们的命令。找到拦截器的方法有很多,可能会有很多误报。这段代码是一个很好的起点:

--Find potential blockers:
select sid, final_blocking_session, gv$session.*
from gv$session
where final_blocking_session is not null;

一旦我们有了 FINAL_BLOCKING_SESSION(这是阻塞会话的 SID),我们就可以找到有关该会话的更多信息,例如它正在运行的语句。此 SQL 语句可以帮助调查阻止程序:

--Use the FINAL_BLOCKING_SESSION from above.
select *
from gv$sql
join gv$session
    on gv$sql.sql_id = gv$session.sql_id
where sid = <final_blocking_session>;

希望其中一些信息有意义并揭示罪魁祸首。由于更改没有显示在审计跟踪中,我猜有一个 SYS 用户正在运行一个命令,因为 SYS 没有在同一个地方审计。

于 2019-07-22T02:49:11.553 回答