PLSQL_性能优化系列08_Oracle Insert / Direct Insert性能优化

2014-09-25 Created By BaoXinjian

一、Insert 性能影响


应用设计不合理导致的session之间的互锁(enqueue)是影响程序可扩展性最常见的原因。此外,一些共享资源的争用,也会导致性能下降。

本篇介绍两个由并发insert操作导致的等待事件(wait event),以及如何通过优化物理设计来进行改善。

普通Insert操作本身产生的是行锁,因此进程相互之间不会锁住(enqueue),但当很多进程insert同一张表时,会有资源上冲突。

 

以下是两个例子:

1. Buffer busy wait

批量进程insert test_table表,当进程多时(超过100个)速度明显下降。在awr报告中看到(等待事件占了93%,cpu占0.95%。也就是说全都在等了,没人在干活…)。

进一步查到等待的object是PK_TEST_TABLE,是test_table表的主键。

Test_table表上建了hash分区(16),而PK_TEST_TABLE却没有建分区,导致修改同一index block,这会导致TX-index contention和buffer busy waits。

重建pk_test_table为hash分区索引后buffer busy waits和enq:TX-index contention就不在top events里了。

 

 

2. 很多进程insert,报ora-00060 Dead lock错误

insert/update/delete操作时,虽然是行封锁,但进程会在修改的block上占一个slot,当修改同一block的进程数量超过initrans时,可能导致60错误。见下文

Its possible to get an ora-60 deadlock when more than one transaction does DML on a block if INITRANS was set too low.

If there are more simultaneous transactions than slots then the transaction layer needs to grow from INITRANS towards MAXTRANS.

but it can't if the rest of the block is packed with data. In this case the transaction that could not get a slot will either hang or get an ora-60 depending on the particular circumstances.

This is an issue with tables, indexes, and clusters.

以上两种性能问题可以table/index的物理设计优化来解决。有几种方法:

(1). 建表时将表、索引的initrans值设大;

(2). 将表、索引建成hash分区,降低单个block上的冲突;

(3). 将索引建成反向索引。由于很多主键使用sequence的值,因此insert都是按sequence值排序的,insert时会在索引的同一block上产生冲突。使用反向键索引可以消除这一问题。有兴趣的可以在google上查相关概念。

 

 二、Insert Direct性能影响


数据库运行出账程序时,出现enq: TM - contention等待事件,

主要原因是多个进程在insert bill_invoice_*时,使用了insert /*+ append*/这一方式,本来想通过append即direct insert方式提升速度,结果产生表级锁。

这样开帐进程相互等待,实际上是变成串行的操作了,反而影响了速度。

更严重的是,如果是生产系统,还会导致账 单表上所有修改操作都无法进行,影响其他重要业务,这个后果就很严重了。

Direct insert这一用法有其速度快的优点,但也有其缺点,必须注意适用场合。大家想一下,为什么oracle不默认用append呢?

这里总结一下,direct-load insert(及append,direct方式sqlldr等)

适合于:

(1). 大量记录的insert时使用会提升速度,因为绕过databuffer直接访问数据文件,且不用扫描原有block上哪些有剩余空间,而直接分配新空间;

(2). 单个进程,通常是数据维护时,或者临时倒数据等;

这两种情况下,使用direct-load insert不仅速度快,还减少了数据库data buffer的使用,对数据库上的其他应用产生的影响也较小;

不适合:

(1). 少量记录insert。因为每次insert /*+append */后会进行索引维护,少量记录insert使用append反而慢;

(2). 多用户,OLTP环境。因为append会产生表级锁。OLTP系统除了一些批处理操作,大多数应用都不应该使用append;

 
 三、Insert Direct局限性

1. append只在insert … select …中起作用,像insert /*+ append */ into t values(…)这类的语句是不起作用的。在update、delete操作中,append也不起作用。

2. append会使数据库不记录直接路径导入的数据的重做日志,会对恢复带来麻烦。

3. append直接在表段的高水位线以上写数据,不会重用高水位线以下的空间,会对空间的使用造成一定的浪费,对查询的性能也会造成一定的影响。

4. 用append导入数据后,如果没有提交或者回滚,则在同一个会话中不能对该表的执行任何DML或者SELECT操作,(执行查询或者DML会报错),但可以对其他表执行查询或者DML操作。

5. 用append导入数据后,如果没有提交或者回滚,在其他会话中任何对该表的DML都会被阻塞(不会报错),但对该表的查询可以正常执行。

 

Thanks and Regards

参考:http://www.linuxidc.com/Linux/2011-08/40763.htm

参考:http://mingyue19850801.blog.163.com/blog/static/19520820201071712231671/

posted on 2014-10-10 08:14  东方瀚海  阅读(2641)  评论(2编辑  收藏  举报