有沒有可能監控巨大插入的進度?假設我們有一個代碼:
MERGE INTO huge_table ht
USING (
SELECT column1, column2
FROM another_huge_table
) aht ON (ht.column1 = aht.column1)
WHEN NOT MATCHED THEN
INSERT (column1, column2)
VALUES (aht.column1, aht.column2);
COMMIT;
表可以包含數百萬行,插入程序可以持續數小時。是否有可能在 Oracle 中監控 DML 進度?
uj5u.com熱心網友回復:
簡短回答:沒有資料庫引擎可以開箱即用。您需要了解,在開始執行之前,Oracle 并不知道將合并多少行。如評論中所述,一個選項是在 PLSQL 中將查詢分成塊,并使用日志記錄方法來監視提交的行與花費的時間。但這比運行普通的合并陳述句要慢得多,我可以想出為什么它值得。
不過,這種方法可以以某種方式幫助您。為了這個目的,我假設您的合并陳述句沒有并行運行。Oracle 提供v$session_longops字典視圖來監視長時間操作,定義為可能需要超過 6 秒的操作。但是,對于操作,您必須了解執行計劃中的每個步驟。
讓我們做一個 PoC
表
SQL> create table test.huge_table ( c1 number, c2 varchar2(40) , c3 varchar2(40) ) ;
Table created.
SQL> create table another_huge_table ( c1 number, c2 varchar2(40) , c3 varchar2(40) ) ;
Table created.
讓我們在目標表中插入 5M 行,在源表merge中插入10m,這樣我們就可以發出插入 5M 行的 a。
SQL> declare
2 begin
3 for i in 1 .. 5000000
4 loop
5 insert into test.huge_table
6 values
7 ( i ,
8 lpad(dbms_random.string('A',1),round(dbms_random.value(20,30)),dbms_random.string('A',1)),
9 lpad(dbms_random.string('A',1),round(dbms_random.value(20,30)),dbms_random.string('A',1))
10 );
11 end loop;
12 commit;
13* end;
SQL> /
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats ( ownname => 'TEST' , tabname => 'HUGE_TABLE' , block_sample => true ) ;
PL/SQL procedure successfully completed.
SQL> declare
2 begin
3 for i in 1 .. 10000000
4 loop
5 insert into test.another_huge_table
6 values
7 ( i ,
8 lpad(dbms_random.string('A',1),round(dbms_random.value(20,30)),dbms_random.string('A',1)),
9 lpad(dbms_random.string('A',1),round(dbms_random.value(20,30)),dbms_random.string('A',1))
10 );
11 if i = 5000000
12 then
13 commit ;
14 end if;
15 end loop;
16 commit;
17* end;
SQL> /
PL/SQL procedure successfully completed.
SQL> exec dbms_stats.gather_table_stats ( ownname => 'TEST' , tabname => 'ANOTHER_HUGE_TABLE' , block_sample => true ) ;
PL/SQL procedure successfully completed.
讓我們驗證計劃
SQL> explain plan for
merge into test.huge_table t
using (
select c1,c2,c3 from test.another_huge_table
) s
ON (t.c1 = s.c1)
when not matched then
insert (c1, c2, c3)
values ( s.c1, s.c2, s.c3 ); 2 3 4 5 6 7 8 9
Explained.
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4265949913
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | MERGE STATEMENT | | 10M| 1096M| | 67324 (1)| 00:00:06 |
| 1 | MERGE | HUGE_TABLE | | | | | |
| 2 | VIEW | | | | | | |
|* 3 | HASH JOIN RIGHT OUTER| | 10M| 1106M| 333M| 67324 (1)| 00:00:06 |
| 4 | TABLE ACCESS FULL | HUGE_TABLE | 5000K| 276M| | 8232 (1)| 00:00:01 |
| 5 | TABLE ACCESS FULL | ANOTHER_HUGE_TABLE | 10M| 553M| | 16291 (1)| 00:00:02 |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T"."C1"( )="C1")
然后我們運行合并
SQL> merge into test.huge_table t
using (
select c1,c2,c3 from test.another_huge_table
) s
ON (t.c1 = s.c1)
when not matched then
insert (c1, c2, c3)
values ( s.c1, s.c2, s.c3 ); 2 3 4 5 6 7 8
5000000 rows merged.
Elapsed: 00:00:36.39
SQL> commit ;
Commit complete.
Elapsed: 00:00:00.01
同時行程正在運行,我可以獲得有關步驟的資訊
SQL> r
1 select opname,
2 target,
3 round( ( sofar/totalwork ), 2 ) * 100 percentage_complete,
4 start_time,
5 ceil( time_remaining / 60 ) max_time_remaining_in_min,
6 floor( elapsed_seconds / 60 ) time_spent_in_min
7 from v$session_longops
8* where sofar != totalwork
OPNAME TARGET PERCENTAGE_COMPLETE START_TIM MAX_TIME_REMAINING_IN_MIN TIME_SPENT_IN_MIN
------------------- --------- ---------------------------------------------------
Table Scan TEST.ANOTHER_HUGE_TABLE 86 28-OCT-21 1 0
OPNAME TARGET PERCENTAGE_COMPLETE START_TIM MAX_TIME_REMAINING_IN_MIN TIME_SPENT_IN_MIN
------------------- --------- ---------------------------------------------------
Hash Join TEST.ANOTHER_HUGE_TABLE 42 28-OCT-21 1 0
OPNAME TARGET PERCENTAGE_COMPLETE START_TIM MAX_TIME_REMAINING_IN_MIN TIME_SPENT_IN_MIN
------------------- --------- ---------------------------------------------------
Hash Join TEST.ANOTHER_HUGE_TABLE 77 28-OCT-21 1 0
概括
如果 Oracle 認為這些步驟中的任何一個將花費超過 6 秒,則會將它們包含在v$session_longops. 您可以查詢這個 viev 以獲得每一步的估計,但這并不是整個 DML 將花費多少時間的真正衡量標準。但這可能是一個好的開始。
另一種可能更好的方法是生成基線。您可以在 PLSQL 或任何其他語言中包含合并,包括用于收集開始時間、結束時間和合并行的日志記錄方法。隨著時間的推移和數十次執行,您可以應用統計資料并獲得平均值和/或標準偏差。我正在使用類似的方法來生成這種型別的資訊,我可以用它來做出有根據的猜測,僅此而已。
希望這會以某種方式幫助你。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/341142.html
上一篇:OraclesqlldrORA-28009:connectionasSYS應該是SYSDBA或SYSOPER
下一篇:如果值不存在,則將值插入表中
