我有一个简单的程序。但有时会出现 ORA-00054 错误。我怀疑启用并行 DML 步骤。不过不知道有没有影响。
截断表后,我将新数据插入到截断的表中。没有其他操作来锁定该表,只有这个插入语句。
我知道截断是一个DDL操作,它是元数据的事务过程。只有一次机会锁定,截断和插入步骤必须并行启动。
有什么想法吗?
BEGIN
-- Enable parallel DML for the session
EXECUTE IMMEDIATE 'ALTER SESSION ENABLE PARALLEL DML';
-- Truncate the table
EXECUTE IMMEDIATE 'TRUNCATE TABLE my_table';
-- Insert new data into the table with parallel DML enabled
EXECUTE IMMEDIATE 'INSERT /*+ PARALLEL(my_table, 4) */ INTO my_table (column1, column2)
SELECT column1, column2 FROM another_table';
END;
尝试在您的程序中使用此代码:
BEGIN
-- Temporary change to help debugging:
-- Let the INSERT statement wait instead of immediately throwing the error
-- ORA-00054: resource busy and acquire with NOWAIT
EXECUTE IMMEDIATE 'ALTER SESSION SET ddl_lock_timeout = 1000000';
-- Truncate the table.
EXECUTE IMMEDIATE 'TRUNCATE TABLE my_table';
-- Insert new data into the table with parallel DML enabled.
EXECUTE IMMEDIATE 'INSERT /*+ ENABLE_PARALLEL_DML APPEND PARALLEL(4) */ INTO my_table (column1, column2)
SELECT column1, column2 FROM another_table';
COMMIT;
END;
/
下次会话被阻塞时,它将等待而不是立即抛出错误。如果您可以在等待发生时捕获它,请使用以下查询找到阻塞会话:
-- The session that is blocking your session.
select *
from gv$session
where (inst_id, sid) in
(
select final_blocking_instance, final_blocking_session
from gv$session
where final_blocking_session is not null
);
如果阻塞会话只持续很短的时间,并且您无法实时捕获它的发生,您仍然可以通过查看历史性能数据找到阻塞者。使用以下查询查找历史阻止程序,但您需要修改查询以过滤掉许多不相关的阻止程序。
GV$ACTIVE_SESSION_HISTORY
通常包含大约一天的数据。如果该数据不够旧,请将其替换为 DBA_HIST_ACTIVE_SESS_HISTORY
。
select *
from gv$active_session_history
where blocking_session is not null;
有很多与你相对较小的代码相关的微妙问题:
EXECUTE IMMEDIATE
不是必需的,因为您知道所有对象都是运行时的。但是,在您的过程中,您可能确实希望保留动态 SQL。您的真实代码使用一个过程,并且对被截断的表进行静态引用的过程将触发重新编译。强制自身重新编译的代码可能会导致问题,因此请保留动态 SQL。ENABLE_PARALLEL_DML
可以通过提示为单个 SQL 语句启用。您可能还想将 PARALLEL(my_table, 4)
更改为 PARALLEL(4)
- 如果该语句要并行运行,您不妨并行化整个语句,而不是仅并行其一部分。 APPEND
提示确保语句始终以直接路径插入的方式运行。通常,并行运行 INSERT 将导致直接路径模式。但是,以防万一您的服务器暂时耗尽并行会话,您可能仍然希望获得直接路径写入,因此 APPEND
在某些情况下可能会有所帮助。