Insert语句加/*+APPEND */在循环中单条提交对系统的影响分析

1、/*+APPEND */提示的用途

/*+APPEND */提示,是一个INSERT语句专有的hint,它的作用,大家都知道是用来提升insert速度的,并且效果非常的明显,至于它的提升速度的工作原理,在笔者的另一篇博文《用直接路径(direct-path)insert提升性能的两种方法》中有提到(以优点方式提出),该文地址为:http://blog.csdn.net/ljunjie82/article/details/42615233

2、单条循环提交中使用/*+APPEND */的巨大影响

再好的东西,有好的一面,也有不好的一面,用得好,可以助你事半功倍,用不好,将会带来巨大的影响。

/*+APPEND */由于期是在高水位以上插入,以及/*+APPEND */会给表加6级排它锁的特性,所以试想,如果要在loop或if循环中,要循环的插入一百万行数据,每循环一次只有一行符合条件的数据插入,commit只能放在循环之内(/*+APPEND */决定着commit无法放在特环外面),即代表着一万行数据,有一千万次commit。

这种使用场景,笔者已经在多个项目中看到,所以在此将该种用法的影响分析出来供有需要的人士参考。

这样的操作,对ORACLE数据库将会带来怎样的严重后果?

3、影响分析测试

3.1 loop循环中使用/*+APPEND */ hint的INSERT单条提交场景

(1)创建三张测试表


create table emp(empno
number);             --
游标值引用表

create table emp_inter(numberno
number);    --中间表

create table emp_append_test(empno
number); --目标表

(2)向游标值引用表与中间表各插入10000行数据


set timing on;

declare

i number:=1;

begin

loop

insert into emp
(empno)
values (i);

insert into emp_inter
(numberno)
values (i);

commit;

i:=i+1;

exit when i=10001;

end loop;

end;

/

输出时间值:Elapsed: 00:00:02.8    --同时向两张表insert 10000行数据,耗时2.8秒

3.2 对空间占用的严重影响测试与分析

3.2.1对三张表所占用空间进行测试前记录


select ‘EMP‘
as table_name,count(distinct dbms_rowid.rowid_block_number(rowid))
as blocks from EMP

union all

select ‘EMP_INTER‘
as table_name,count(distinct dbms_rowid.rowid_block_number(rowid))
as blocks from EMP_INTER

union all

select ‘EMP_APPEND_TEST‘
as table_name,count(distinct dbms_rowid.rowid_block_number(rowid))
as blocks from EMP_APPEND_TEST

输出结果如下:


table_name


blocks


EMP


16


EMP_INTER


16


EMP_APPEND_TEST


0

在此已经看到,EMP、EMP_INTER两张表,各插入999行数据,占用block为16个,当前没有插入数据的EMP_APPEND_TEST表占用0个block。

3.2.2在loop循环中加/*+APPEND */hint做insert数据

向目标表emp_append_test插入数据


set serveroutput
on

set timing
on

declare

n number:=1;

begin

for c
in (select empno
from emp)

loop

insert /*+APPEND */
into emp_append_test select
* from emp_inter
where numberno=c.empno;

n:=n+1;

commit;

end loop;

dbms_output.put_line(‘insert rows is :‘||n);

end;

/

输出值:insert rows is :10000     --插入10000行数据

Elapsed: 00:00:11.62      --此次向一张表中插入10000行数据,耗时11.62秒

3.2.3 再次查询三张表占用的block数量


select ‘EMP‘
as table_name,count(distinct dbms_rowid.rowid_block_number(rowid))
as blocks from EMP

union all

select ‘EMP_INTER‘
as table_name,count(distinct dbms_rowid.rowid_block_number(rowid))
as blocks from EMP_INTER

union all

select ‘EMP_APPEND_TEST‘
as table_name,count(distinct dbms_rowid.rowid_block_number(rowid))
as blocks from EMP_APPEND_TEST;

输出结果如下:


table_name


blocks


EMP


16


EMP_INTER


16


EMP_APPEND_TEST


10000

从上面看来,结果是非常可怕的,插入一万行数据,占用一万个block,以每个block 8KB计算,一万行数据占用78.1MB左右(10000*8/1024)。

3.3 对查询性能影响

(1)对未使用/*+APPEND */循环单条commit的表EMP查询性能测试


SQL> set autotrace on statistics

SQL> select * from emp where empno =1;

-------------

Statistics

----------------------------------------------------------

1  recursive calls

0  db block gets

23  consistent gets

0  physical reads

0  redo size

523  bytes sent via SQL*Net to client

523  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

(2)对使用/*+APPEND */循环单条commit的表EMP_APPEND_TEST查询性能测试


SQL> set autotrace on statistics

SQL> select * from EMP_APPEND_TEST where empno = 1;

---------------------------

Statistics

----------------------------------------------------------

1  recursive calls

0  db block gets

20003 
consistent gets

10000  physical reads

0  redo size

523  bytes sent via SQL*Net to client

523  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

(3)查询性能结果比较:


table_name


consistent gets


physical reads


EMP


23


21


EMP_APPEND_TEST


20003


10024

consistent gets翻了869倍

physical reads翻了477倍

4、问题小结

Insert语句加/*+APPEND*/ hint在循环中单条提交,由于/*+APPEND */ hint是在高水位线以上插入的特性,导致每提交一次,就会取一个新的block存放,高水位就上推一个block,以及/*+APPEND */ hint会给表加6级排它锁的特导,导致必须在commit后才能插入新的数据,大量单条/*+APPEND */插入,使得表急剧增大,除对insert本身造成性能影响之外,对以后的select、update、delete更是造成更巨大的影响。

本文作者:黎俊杰(网名:踩点),从事”系统架构、操作系统、存储设备、数据库、中间件、应用程序“六个层面系统性的性能优化工作

欢迎加入 系统性能优化专业群,共同探讨性能优化技术。群号:258187244

时间: 2024-08-06 17:46:21

Insert语句加/*+APPEND */在循环中单条提交对系统的影响分析的相关文章

MySQL insert语句中中value和values的区别(二)

最近公司事情太忙,作为以一挑十的测试,只能苦逼的累死累活的.好不容易临近上线,可以偷个懒写个文章. 简单的说说如何向表中插入数据: 1.向表中所有的列插入数据(插入多行数据): insert  into  表名 values (列值1,列值2,列值3...列值n), (列值a,列值b,列值c...列值n), ........... (列值A,列值B,列值C...列值N) 2.向表中指定的列插入数据(插入单行数据): insert  into  表名(列名1,列名2,列名3...列名n) valu

Mysql insert语句的优化

1) 如果你同时从同一客户插入很多行,使用多个值表的INSERT语句.这比使用分开INSERT语句快(在一些情况中几倍).    Insert into test values(1,2),(1,3),(1,4)- 2) 如果你从不同客户插入很多行,能通过使用INSERT DELAYED语句得到更高的速度.Delayed的含义是让insert 语句马上执行,其实数据都被放在内存的队列中,并没有真正写入磁盘:这比每条语句分别插入要快的多:LOW_PRIORITY刚好相反,在所有其他用户对表的读写完后

break与continue在循环中的区别

break (1).结束当前整个循环,执行当前循环下边的语句.忽略循环体中任何其它语句和循环条件测试. (2).只能跳出一层循环,如果循环是嵌套循环,那么需要按照你嵌套的层次,逐步使用break来跳出. continue (1).终止本次循环的执行,即跳过当前这次循环中continue语句后尚未执行的语句,接着进行下一次循环条件的判断. (2).结束当前循环,进行下一次的循环判断. (3).终止当前的循环过程,但他并不跳出循环,而是继续往下判断循环条件执行语句.它只能结束循环中的一次过程,但不能

关于加快INSERT语句执行速度和HINT /*+ append */及/*+ append nologging */的使用

(非归档模式下)创建表T01: SQL> create table t01 as select * from dba_objects where 1=2; Table created. (非归档模式下)查看当前redo大小: SQL> select value 2 from v$mystat,v$statname 3 where v$mystat.statistic#=v$statname.statistic# 4 and v$statname.name='redo size' 5 / VAL

退出循环break,在while、for、do...while、循环中使用break语句退出当前循环,直接执行后面的代码。

在while.for.do...while循环中使用break语句退出当前循环,直接执行后面的代码. 格式如下: for(初始条件;判断条件;循环后条件值更新) { if(特殊情况) {break;} 循环代码 } 当遇到特殊情况的时候,循环就会立即结束.看看下面的例子,输出10个数,如果数值为5,就停止输出.

【SQL Sever】将SQL Sever中的一个数据表的数据导出为insert语句

例如:这SQL   Sever中的一张数据表,想要将这张数据表中的数据  转化成一个一个的insert语句存储在txt的文档中,那么不论走到那里这个insert语句一执行,我们就能将这个数据表中的数据插入到另一个地方了. 1>在新建查询中,创建一个对象,这个对象就是用来产生这个对象的,名字叫proc_insert,我们可以创建多个不重名的对象,当然也可以删除这个对象. 1 create proc proc_insert (@tablename varchar(256)) 2 as 3 begin

Python批量执行oracle中的insert语句

从oracle导出一个表的数据,导出的格式是insert语句,数据量30万. 直接在PL/SQL Developer中执行,速度非常慢,脚本中也是100条数据提交一次.因为需要的时间太长,每次中断后,下次执行,又要重新全部导入,需要把之前导入的数据清除. 为了能够断点续传,想了个办法: 用Python把脚本分拆,用commit作为分隔符(脚本中每100条数据有一个commit),分拆成多个脚本,用Python遍历文件夹下的脚本,分别执行每个脚本的语句,执行完成后,把脚本移动到BAK目录,这样即使

Python while 循环中使用 else 语句

Python while 循环中使用 else 语句: else:表示 while 中的语句正常执行完,然后执行 else 语句的部分. 示例: # while 判断条件: # 一行语句 或 多行语句组 # else: # 一行语句 或 多行语句组 # ''' 程序: a = 4 while a < 6: print(a) a += 1 else: print("运行结果 OK") # 4 # 5 # 运行结果 OK 2020-02-06 原文地址:https://www.cnb

【视频+图文】带你快速掌握Java中含continue语句的双重for循环

双重for循环掌握后,我们就一起来看看双重for循环的进阶内容一之带continue语句的双重for循环. 上期双重for循环[视频+图文]讲解传输门:点击这里可去小乔的哔哩哔哩观看for循环视频~ 带continue语句的双重for循环[视频+图文] continue语句能用在哪?它的作用是什么? 用法:只能用在循环结构中(for循环,while循环,do-while循环,for each循环) 作用:本次循环体中的continue语句之后代码不执行,直接跳到下次循环. 例子:(ps:看到这里