批量插入分区表和表级锁定

时间:2013-05-10 07:40:00

标签: sql oracle locking bulkinsert

我想知道核心原因(引擎所做的段,块,锁的机制)为什么批量插入(使用直接路径)锁定整个表,所以如果我插入分区,我不能截断另一个分区,不受插入影响(显然)。

传统的插入(没有附加提示)允许截断一些不受影响的分区。(注意我说的是非提交的事务。)

下面举例说明它。

让我们成为一张桌子:

 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;

第二节:

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;

第二节:

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没有解释为什么所有分区都需要锁定。 为什么传统插件不能锁定不受影响的分区? (我的直觉是锁定在块级别完成)

2 个答案:

答案 0 :(得分:6)

你的前提稍有不妥。如果使用分区扩展子句,则直接路径插入不会锁定整个表。

第1节:

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

第二节:

alter table fg_test truncate partition p1;
--table truncated

新问题是:当不使用分区扩展子句时,为什么传统和直接路径插入具有不同的锁定机制?这种澄清使问题更容易,但没有内部知识的答案下面仍然只是猜测。


编写锁定整个表的功能更容易。它运行得更快,因为不需要跟踪更新的分区。

通常不需要更细粒度的锁。大多数使用直接路径写入的系统或进程一次只更新一个大表。如果确实需要更细粒度的锁,则可以使用分区扩展子句。它不太方便,因为一次只能引用一个分区。但99.9%的时间足够好。

答案 1 :(得分:3)

我在asktom.oracle.com上找到了以下答案:

Ask Tom: Inserts with APPEND Hint

Tom解释了许多内部工作原理,但为什么 Oracle锁定整个表而不仅影响分区的原因仍然不明确。

也许这只是一个设计决策(例如,不希望大型的大型直接负载可能被一个小的未经通信的事务阻塞,因此锁定所有分区......)