2013-05-10 55 views
7

我想知道爲什麼批量插入(使用直接路徑)鎖定整個表,因此如果插入的話,我想知道核心原因(引擎的段,塊,鎖的機制)到一個分區,我不能截斷另一個不受影響(顯然)插入的分區。批量插入到分區表和表級別鎖

常規的插入物(沒有追加提示)允許截斷一些nonaffected分區。(注意,我談論非COMMITED事務。)

下面一個例子來ilustrate它。

讓是一個表:

CREATE TABLE FG_TEST 
    (COL NUMBER) 
    PARTITION BY RANGE (COL) 
(PARTITION "P1" VALUES LESS THAN (1000), 
    PARTITION "P2" VALUES LESS THAN (2000)); 

Insert into table fg_test values (1); 
insert into table fg_test values (1000); 
commit; 

會議1:

insert into table fg_test select * from fg_test where col >=1000; 
--1 rows inserted; 

會話2:

alter table fg_test truncate partition p1; 
--table truncated 

會議1:

rollback; 
insert /*+append */ into table fg_test select * from fg_test where col >=1000; 
--1 rows inserted; 

會議2:

alter table fg_test truncate partition p1; 
--this throws ORA-00054: resource busy and acquire with NOWAIT specified 
--or timeout expired 

Doc on Diret-Path Insert是對這個問題很突然,只是說:

在直接路徑INSERT,數據庫取得對 表排他鎖(或上的所有分區的分區表)。因此, 用戶無法對錶執行任何併發插入,更新或刪除操作,並且不允許併發索引創建和構建 操作。

How Direct-Path INSERT Works不能解釋爲什麼所有分區都需要鎖定。 爲什麼傳統的插入不鎖定不受影響的分區? (我的直覺是,鎖在塊級進行)

+1

傳統的行級別插入鎖定,表定義也受共享鎖保護以防止被修改。 Oracle中沒有任何塊級鎖,它是全部行,(子)分區或表級別。 – 2013-06-04 06:39:00

回答

5

你的前提是稍有不妥。如果使用分區擴展子句,則直接路徑插入不會鎖定整個表。

會議1:

insert /*+append */ into fg_test partition (p2) 
select * from fg_test where col >=1000; 

會議2:

alter table fg_test truncate partition p1; 
--table truncated 

的新問題是:當不使用分區擴展條款,爲什麼傳統和直接路徑插入有不同的鎖定機制是什麼?這個澄清使問題更容易,但沒有內部知識,下面的答案仍然只是一個猜測。


編寫鎖定整個表格的功能更容易。而且運行速度更快,因爲不需要跟蹤哪些分區被更新。

通常不需要更細密的鎖。大多數使用直接路徑寫入的系統或進程一次只更新一個大型表。如果真的需要更細粒度的鎖,可以使用分區擴展子句。這並不方便,因爲一次只能引用一個分區。但99.9%的時間足夠好了。

+0

+1很高興知道這個行爲(分區子句影響) – 2013-06-04 11:07:14

+0

@JonHeller所以,如果我使用直接路徑插入到使用分區擴展的表中,該分區仍然會被鎖定在該會話中,直到發出「COMMIT」。那是對的嗎?我甚至不確定是否「分區鎖定」甚至是一件事,請原諒我的無知。 – Annjawn 2014-11-25 03:11:02

3

我找到了答案follwing上asktom.oracle.com:

Ask Tom: Inserts with APPEND Hint

湯姆解釋了許多內部工作的,但原因爲什麼 Oracle鎖定了整個表,不僅受影響的分區還不清楚。

也許這只是一個設計決策(例如不希望被一個短小未提交的事務中可能受阻的大笨重的直接加載,因此鎖定所有分區...)

+0

感謝您的回答。 – 2013-05-10 19:56:46