Append與Direct-Path Insert(一)
Append提示在進行批次資料載入的時候,是很高效的一個手段。前段進行實驗,發現這個hint在使用的時候,還是有一些需要注意的地方的。
1、 基礎知識
還是先看看基礎知識吧。append是oracle提供給SQL開發者使用的hint之一。所謂hint的作用,簡單說就是影響Oracle最佳化器生成特定的執行計劃。SQL是一種資料描述語言。實際對資料進行操作是透過對SQL的解析,生成執行計劃的過程。
Append提示的作用提示最佳化器使用直接路徑插入(Direct-Path Insert)方式。下面簡單說下Oracle的兩種插入和兩種模式。
兩種工作模式,分別成為序列化模式(Serial Mode)和並行模式(Parallel Mode)。序列化模式就是我們通常的SQL工作模式,一個SQL操作內部順序執行。並行模式就會將工作按照一定規則劃分為多個工作執行緒同時執行,之後匯合結果。在進行大資料量操作的時候,可以考慮採用並行模式以提高效率。
插入方式上,Oralce有Conventional Insert和Direct-Path Insert兩種。
傳統插入(Conventional Insert)方式是我們通常使用的Insert方式。預設情況下,傳統插入是使用序列化模式的。在序列化模式下,如果在insert中使用append提示,Oracle會對該條insert使用Direct-Path插入方式。
直接路徑(Direct-Path)方式在是並行操作模式下的預設插入方式。在並行模式下,只有使用noappend提示,才能使用傳統的插入方式。
所以,插入操作的時候,究竟是使用並行還是序列模式,與append提示無關。
在使用直接路徑插入的時候,資料並不是先從資料表中找到隨機的空位後插入,而是直接將資料插入到資料表的末尾,直接推高高水位線。這種操作方式,較傳統的方式要快。
2、 快速的直接路徑插入
相對於傳統模式,使用append提示之後,批次插入的速度可以得到顯著的提升。
SQL> create table t as select * from dba_objects where 1=0;
Table created
SQL> select count(*) from t;
COUNT(*)
----------
0
Executed in 0.01 seconds
//一般插入方式
SQL> insert into t select * from dba_objects;
50367 rows inserted
Executed in 0.571 seconds
//還原環境,刪除資料
SQL> truncate table t;
Table truncated
Executed in 0.431 seconds
//Append插入方式
SQL> insert /*+ append */into t select * from dba_objects;
50367 rows inserted
Executed in 0.45 seconds
透過上面的簡單實驗,可以看到:在相同的條件下,使用append進行資料表的插入,要顯著的快於傳統方式。這種特點在海量資料載入、遷移的過程中,可以顯著的提高效率。要注意,這種方式因為直接提升高水位線,不會利用表中原有被刪除的空間,在一些刪除操作比較多的表中,會造成很大的空間浪費,要避免濫用引發空間膨脹問題。
3、 Append操作與鎖
在使用Append操作時,要注意Append操作是一種特殊的插入操作,會阻止包括自身會話在內的插入操作。首先,我們先看一下普通插入的系統行為。
//資料準備,建立資料表
SQL> create table t as select owner, object_id, rownum num from dba_objects where 1=0;
Table created
//session1中,啟動一個插入操作
SQL> insert into t select owner,object_id,rownum from dba_objects where rownum<10;
9 rows inserted
SQL> select * from v$mystat where rownum<2;
SID STATISTIC# VALUE
---------- ---------- ----------
140 0 1
//觀察系統中鎖的情況
SQL> select * from v$lock where sid=140;
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST
-------- -------- ---------- ---- ---------- ---------- ---------- ----------
6BDC4074 6BDC408C 140 TM 53083 0 3 0
6BE3BE7C 6BE3BF98 140 TX 458760 692 6 0
說明:Session1(SID=140)首先在資料表物件加上一個TM鎖,模式為3共享鎖,同時對其插入的資料項加了事務TX鎖,模式為6獨佔鎖;
//啟動另一個session2,執行插入操作
SQL> insert into t select owner, object_id, rownum from dba_objects where object_id=120;
1 row inserted
SQL> select sid from v$mystat where rownum<2;
SID
----------
142
SQL> select * from v$lock where sid in (140,142);
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST
-------- -------- ---------- ---- ---------- ---------- ---------- ----------
6BDC4074 6BDC408C 140 TM 53083 0 3 0
6BDC4138 6BDC4150 142 TM 53083 0 3 0
6BE127B8 6BE128D4 142 TX 655371 658 6 0
6BE3BE7C 6BE3BF98 140 TX 458760 692 6 0
說明:session2(SID=142)進行插入操作,也嘗試在物件表(ID1 53083)上加一個共享鎖TM,LMODE=3。與Session1(SID=140)的TM鎖可以共存(共享鎖之間),同時將插入事務鎖TX,型別為獨佔鎖,與原有的session1獨佔鎖加上的是不一樣的物件。
說明:在傳統的插入操作中,會話之間插入操作是不會相互影響的。同一個事務內部,進行插入操作之間,也沒有互斥的情況。
下面我們開始實驗append提示。(下面實驗是使用相同的兩個session(sid=140,142))。
//在session1(sid=140)中使用append關鍵字插入。
SQL> insert /*+ append */ into t select owner, object_id, rownum from dba_objects where rownum<10;
9 rows inserted
//同一個session內,進行相同的操作
SQL> insert /*+ append */ into t select owner, object_id, rownum from dba_objects where rownum<10;
ORA-12838: 無法在並行模式下修改之後讀/修改物件
說明:即使在同一個session裡,對一個表進行append插入之後,必須先commit之後,才能進行相同表的操作。這個特點可能與append採用的並行模式操作有關。
這個時候,我們檢視一下當前sesson1(sid=140)的鎖狀態。
//檢視session1的鎖狀況
SQL> select * from v$lock where sid=140;
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST
-------- -------- ---------- ---- ---------- ---------- ---------- ----------
6BDC4074 6BDC408C 140 TM 53083 0 6 0
6BE3BE7C 6BE3BF98 140 TX 196611 652 6 0
請注意:當我們進行append操作的時候,oracle對錶t加鎖狀況出現差異。變化點在資料表鎖TM的模式LMODE為6(排他鎖),這點與一般插入存在差異。TM模式6的現象說明,在進行append操作的時候,oracle對資料表級的鎖操作不是一個共享鎖(LMODE=3),而是一個排他鎖(LMODE=6)。從鎖知識角度,如果這時其他會話嘗試插入操作(向資料表T加一個LMODE=3的共享鎖),是會被hange住。
//此時session2(sid=142)
SQL> select sid from v$mystat where rownum<2;
SID
----------
142
//嘗試以一個一般方式插入資料
SQL> insert into t select owner, object_id, rownum from dba_objects where object_id=120;
//session2被hange住
//此時檢視兩個會話的鎖狀況
SQL> select * from v$lock where sid in (140,142);
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST
-------- -------- ---------- ---- ---------- ---------- ---------- ----------
6BDC4074 6BDC408C 140 TM 53083 0 6 0
6BDC4138 6BDC4150 142 TM 53083 0 0 3
6BE3BE7C 6BE3BF98 140 TX 196611 652 6 0
說明:此時session2嘗試在表T上加入一個共享鎖Lmode=3,因為已經被sid=140獨佔排他。所以被hange住。
//session1 commit之後。
SQL> commit;
Commit complete
//session2解除hange狀態
結論:實驗結果和我們預想的一樣。共享鎖和排他鎖是不能相容的。通常,當我們在一個會話中使用了append一批資料後,其他會話是不能插入操作。如果進行的話,會被hange住。進行append操作的會話,也不能在表中進行其他操作。除非提交或回滾事務。
作為這個結論的擴充實驗,我們進行下列嘗試。
//在session1已經進行append的操作情況下
//如果session2也要求進行append的操作時候
SQL> insert /*+ append */ into t select owner, object_id, rownum from dba_objects where rownum<10;
//session2也hange住
SQL> select * from v$lock where sid in (140,142);
ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST
-------- -------- ---------- ---- ---------- ---------- ---------- ----------
6BDC4074 6BDC408C 140 TM 53083 0 6 0
6BDC4138 6BDC4150 142 TM 53083 0 0 6
6BE3BE7C 6BE3BF98 140 TX 65571 638 6 0
//sesion2 被hange住
結論一致,區別在於session2在進行append的操作的時候,也會嘗試獲取排他的表鎖,自然也會被hange住。
綜上所述:append操作是一種有並行操作趨勢的快速插入hint。在使用的時候,要注意及時的commit,以防止出現嚴重的併發操作問題。同時,在高併發的系統(OLTP)中,也要注意慎用。
那麼,是不是append都是要獲取排他鎖呢?排他鎖和共享鎖之間關係如何協同?還有在同一個會話中,對鎖控制有什麼特點?我們在下一篇中繼續探討。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-681591/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Append與Direct-Path Insert(二)APP
- direct-path [insert] parallelParallel
- Oracle Direct-Path InsertOracle
- insert /*+ append */ into 與insert into 的區別APP
- Direct Path Insert與APPEND, PARALLEL的梳理與小結APPParallel
- 使用Direct-Path INSERT插入資料到表中
- CTAS和insert append的一個測試APP
- insert /*+ append */直接路徑插入APP
- insert 中append 用法詳解APP
- 關於insert /*+ append*/ 各種insert插入速度比較APP
- nologging和insert /*+append*/APP
- 直接路徑插入 -- insert /*+append*/ into [zt]APP
- insert append需要注意的問題APP
- 如何讓insert /*+ append */ 採用並行。APP並行
- [Oracle] Append hint(insert sql) will lead a TM LOCKOracleAPPSQL
- insert /*+ append */於report unrecoverable命令實驗。APP
- 關於insert /* append */的幾點註記APP
- insert語句中append提示對欄位的檢查APP
- 測試APPEND INSERT是否產生UNDO資訊的過程APP
- append()與html() 區別APPHTML
- 【廖雪峰python入門筆記】list新增元素_append()和insert()Python筆記APP
- APPEND載入與DELETE操作APPdelete
- Oracle NoLogging Append 方式減少批量insert的redo_sizeOracleAPP
- insert的時候使用append會不會影響到表的大小APP
- append與 appendTo的區別APP
- nologging與append ztAPP
- insert()與substr()函式函式
- 直接insert與儲存過程insert效能區別儲存過程
- oracle bulk Insert 比insert 快不是一點啊.Oracle
- 11g資料庫大表資料快速清理方法 - insert+append+parallel+exchange (2)資料庫APPParallel
- 11g資料庫大表資料快速清理方法 - insert+append+parallel+exchange (1)資料庫APPParallel
- 關於加快INSERT語句執行速度和 HINT /*+ append*/及nologging的使用APP
- 轉eygle_append與nologgingAPP
- URLSearchParams append()APP
- jQuery append()jQueryAPP
- golang appendGolangAPP
- Append HintAPP
- jquery中append()方法與after()方法的區別jQueryAPP