我創建了這個流水線函式,用于從存盤在我需要通過資料庫鏈接訪問的資料庫中的表中獲取配置:
CREATE OR REPLACE FUNCTION fetch_config (
process_i IN VARCHAR2,
procedure_i IN VARCHAR2,
sub_procedure_i IN VARCHAR2
) RETURN t_config_type
PIPELINED
AS
BEGIN
FOR r_row IN (
SELECT
zprocess,
zprocedure,
zsub_procedure,
zcriteria,
zfield,
zfield2,
zvalue_enabled,
zenabled
FROM
cdc.uap_zufi_dunn_conf@rbip
WHERE
zprocess = process_i
AND zprocedure = procedure_i
AND zsub_procedure = sub_procedure_i
) LOOP
PIPE ROW ( config_type(r_row.zprocess, r_row.zprocedure, r_row.zsub_procedure, r_row.zcriteria, r_row.zfield,
r_row.zfield2, r_row.zvalue_enabled, r_row.zenabled) );
END LOOP;
END fetch_config;
但是,當嘗試動態使用該函式時,會引發以下錯誤:
BEGIN
EXECUTE IMMEDIATE q'[
CREATE TABLE my_table AS
SELECT
*
FROM
another_table
WHERE
cacont_acc IN (
SELECT
zvalue_enabled
FROM
TABLE ( fetch_config('GLOBAL', 'EXCLUSIONS', 'ZBUT000_ATTRIBUTES') ))
]'
;
END;
錯誤:
ORA-06512: at line 79
12840. 00000 - "cannot access a remote table after parallel/insert direct load txn"
*Cause: Within a transaction, an attempt was made to perform distributed
access after a PDML or insert direct statement had been issued.
*Action: Commit/rollback the PDML transaction first, and then perform
the distributed access, or perform the distributed access before the
first PDML statement in the transaction.
我試圖在我的本地資料庫中創建一個指向該表的視圖,但它也失敗了。這個問題的解決方法是什么?
uj5u.com熱心網友回復:
它是 Create Table As Select (CTAS) 與參考遠程物件的流水線函式的組合,該函式會導致錯誤“ORA-12840:在并行/插入直接加載 txn 后無法訪問遠程表”。CTAS 陳述句始終使用稱為直接路徑寫入的優化寫入型別,但這些直接路徑寫入不適用于遠程物件。有幾種變通方法,例如將您的陳述句分成單獨的 DDL 和 DML 步驟,或使用公共表運算式強制 Oracle 按有效順序運行操作。
直接路徑寫入
下面的代碼表明 CTAS 陳述句似乎總是使用直接路徑寫入。常規插入將包括“LOAD TABLE CONVENTIONAL”之類的操作,但直接路徑寫入顯示為“LOAD AS SELECT”操作。
drop table my_table;
explain plan for create table my_table as select 1 a from dual;
select * from table(dbms_xplan.display(format => 'basic'));
Plan hash value: 2781518217
-----------------------------------------------------
| Id | Operation | Name |
-----------------------------------------------------
| 0 | CREATE TABLE STATEMENT | |
| 1 | LOAD AS SELECT | MY_TABLE |
| 2 | OPTIMIZER STATISTICS GATHERING | |
| 3 | FAST DUAL | |
-----------------------------------------------------
(但是 - 我不認為 CTAS 使用“真正的”直接路徑寫入。每次使用真正的直接路徑寫入都會導致資料問題。必須有一種機制來允許常規寫入,但我沒有嘗試過,例如NOLOGGING、NOAPPEND 或創建關系約束能夠強制 CTAS 使用“LOAD TABLE CONVENTIONAL”操作。我認為 CTAS 確實在常規路徑和直接路徑之間使用了某種型別的優化。)
直接路徑寫入針對性能進行了優化,但以犧牲一致性為代價。事務,即使是同一個事務,在提交直接路徑寫之前,也不能從同一個物件寫入或讀取。這通常不是 CTAS 的問題,因為這一切都發生在一個步驟中。但是當有一個遠程資料庫時,Oracle 不知道該遠程資料庫正在發生什么樣的事務。并且訪問遠程物件總是會創建一個事務,因此一旦 Oracle 在管道函式中呼叫遠程物件,它就無法判斷遠程發生了什么并引發“ORA-12840:在并行/插入直接加載后無法訪問遠程表txn”。
解決方法
避免 CTAS 可能是防止此錯誤的最直接方法。在單獨的陳述句中隔離 CTAS 直接路徑寫入,然后使用常規插入,該插入將使用適用于資料庫鏈接的“LOAD TABLE CONVENTIONAL”操作。
--(Add warning here about not combining the below two statements.)
EXECUTE IMMEDIATE q'[
CREATE TABLE my_table AS
SELECT
*
FROM
another_table
WHERE
1=0
]';
EXECUTE IMMEDIATE q'[
INSERT INTO my_table
SELECT
*
FROM
another_table
WHERE
cacont_acc IN (
SELECT
zvalue_enabled
FROM
TABLE ( fetch_config('GLOBAL', 'EXCLUSIONS', 'ZBUT000_ATTRIBUTES') ))
]';
但是,如果您想避免重復任何代碼,并在一個步驟中完成所有操作,則可以使用公共表運算式 (CTE)。
EXECUTE IMMEDIATE q'[
CREATE TABLE my_table AS
WITH configs AS
(
--Use CTE and MATERIALIZE hint to avoid ORA-12840.
SELECT /* MATERIALIZE */
zvalue_enabled
FROM
TABLE ( fetch_config('GLOBAL', 'EXCLUSIONS', 'ZBUT000_ATTRIBUTES')
)
SELECT
*
FROM
another_table
WHERE
cacont_acc IN (SELECT zvalue_enabled FROM configs)
]'
;
CTE 和 MATERIALIZE 提示強制 Oracle 首先檢索遠程物件的結果并將它們存盤在臨時表中。當 CTAS 被執行時,它從臨時表中讀取并且不再注意到資料庫鏈接。執行計劃將如下所示:
--------------------------------------------------------------------------------
| Id | Operation | Name |
--------------------------------------------------------------------------------
| 0 | CREATE TABLE STATEMENT | |
| 1 | TEMP TABLE TRANSFORMATION | |
| 2 | LOAD AS SELECT (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D6707_8AAECC0C |
| 3 | COLLECTION ITERATOR PICKLER FETCH | FETCH_CONFIG |
| 4 | LOAD AS SELECT | MY_TABLE |
...
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/385722.html
