谁能告诉我,为什么我的Oracle批量数据处理基准测试在插入和更新方面没有带来任何好处,而在删除操作方面却获得了巨大(400-500%)的好处?

我正在使用一组小数据进行测试:2000条记录.时间在0.02秒到1.1秒的范围内.

谢谢!

"谢谢你,"贾斯汀说.

以下是您可以用来测试的一些代码:

create table tmp$_t1 (id number generated by default on null as identity primary key, c1 varchar2 (30), c2 varchar2 (30))
/

set timing on serveroutput on size unlimited linesize 32767 pagesize 50000 trimspool on tab off feedback on
define svTableName = tmp$_t1
define svInsertHowMany = 2000
define svUpdateWhichMod = 2
define svDeleteWhichMod = 10
truncate table &svTableName
/
<<s01_row_by_row_rbr_dml>> begin <<rbr_loop>> for iRec in (select dbms_random.string ('p', 10) c1 from dual connect by level <= &svInsertHowMany) loop
          insert into &svTableName (c1) values (iRec.c1); end loop rbr_loop; commit;
     <<update_loop>> for iUpdateRec in (select id, c1 from &svTableName) loop
          update &svTableName set c2 = substr (c1, 1, 2) || ' ## ' || id where mod (id, &svUpdateWhichMod) = 0 and id = iUpdateRec.id; end loop update_loop; commit;
     <<delete_loop>> for iDeleteRec in (select id, c1 from &svTableName) loop
          delete &svTableName where mod (id, &svDeleteWhichMod) = 0; end loop delete_loop; commit;
     end s01_row_by_row_rbr_dml;
/
undefine svInsertHowMany svFetchRate svUpdateWhichMod svDeleteWhichMod

set timing on serveroutput on size unlimited linesize 32767 pagesize 50000 trimspool on tab off feedback on
define svTableName = tmp$_t1
define svInsertHowMany = 2000
define svFetchRate = 100000
define svUpdateWhichMod = 2
define svDeleteWhichMod = 10
truncate table &svTableName
/
<<s02_obdp_dml>> declare
     cursor cOBDP is select dbms_random.string ('p', 10) c1 from dual connect by level < &svInsertHowMany; type tOBDP is table of cOBDP%rowtype; lOBDP tOBDP;
     cUpdateDelete sys_refcursor; type tOBDPRec is table of &svTableName%rowtype; lOBDPRec tOBDPRec;
     begin open cOBDP; fetch cOBDP bulk collect into lOBDP limit &svFetchRate;
     <<OBDP_loop>> loop forall iOBDPRec in lOBDP.first .. lOBDP.last insert into &svTableName (c1) values (lOBDP (iOBDPRec).c1);
          fetch cOBDP bulk collect into lOBDP limit &svInsertHowMany; exit when cOBDP%notfound; end loop OBDP_loop; close cOBDP; commit;
          open cUpdateDelete for select * from &svTableName; fetch cUpdateDelete bulk collect into lOBDPRec limit &svFetchRate;
          <<update_delete_loop>> loop forall iOBDPRec in lOBDPRec.first .. lOBDPRec.last update &svTableName
                    set c2 = substr (c1, 1, 2) || ' ## ' || trim (to_char (lOBDPRec (iOBDPRec).id))
                    where mod (lOBDPRec (iOBDPRec).id, &svUpdateWhichMod) = 0 and id = lOBDPRec (iOBDPRec).id;
               forall iOBDPRec in lOBDPRec.first .. lOBDPRec.last delete &svTableName where mod (lOBDPRec (iOBDPRec).id, &svDeleteWhichMod) = 0 and id = lOBDPRec(iOBDPRec).id;
               fetch cUpdateDelete bulk collect into lOBDPRec limit &svFetchRate; exit when cUpdateDelete%notfound;
               end loop update_delete_loop; close cUpdateDelete; commit;
     end s02_obdp_dml;
/
undefine svInsertHowMany svFetchRate svUpdateWhichMod svDeleteWhichMod

第二个匿名块包含INSERT、UPDATE和DELETE操作,这些操作将汇总计时.

为了只测试INSERT、UPDATE或DELETE,只需分别注释掉代码并重新运行.

我把它们都作为单独的代码块,但这可能只是一大堆代码.不管怎么说,我是这么想的.

Rbr="逐行",OBDP="Oracle批量数据处理".

谢谢你的帮助.

推荐答案

您的测试相当不错,但您需要增加运行次数或行数才能看到更有意义的结果.当我将插入的行数从2K增加到200K时,我得到了以下几秒钟的运行时间.这些结果清楚地表明,批量处理对插入来说更快.

Test               Run 1   Run 2   Run 3   Run 4   Run 5
=================  ======  ======  ======  ======  ======
Row-by-row insert  15.086  14.862  15.025  14.868  14.946
Bulk insert         3.915   3.958   3.919   3.745   3.826

当运行时间太小时,随机系统活动可能占总运行时间的很大百分比.系统中总有一些小精灵在等待减慢原本快速运行的查询的速度.也许共享池刚刚被清除,并使CPU达到一秒钟的峰值,或者反病毒程序刚刚启动,等等.

如果要彻底测试批量收集,则需要格外小心.互联网上充斥着(无意中)捏造的测试结果,这些测试结果做出了糟糕的声明.这是因为大多数测试人员不熟悉simple mathematical underpinnings of bulk collection.许多结果完全匹配1/N曲线,但直到测试恰好到达测试者think结果应该更线性的部分.如果您只运行一次或两次测试,您可能会认为存在统计偏差.

Database相关问答推荐

使用Postgres获取带有表架构的外键

postgres 索引扫描的启动成本(postgresql 书的内部 struct )

从仅连接器电源查询制作图表

如何将 Grails 3.0 连接到我的本地 Mysql 数据库

数据库排序规则更改问题 (SQL Server 2008)

su postgres:Sorry?

Postgresql 从多个表中删除多行

返回 SQLite 数据库中表大小的查询

PHP + SQL Server - 如何设置连接字符集?

如何通过 PHP 和 Linux 使用 pdo 连接到 mssql?

使用 JSON 作为存储/传输格式的数据库

是否有标准的Electron 商务数据库架构来将折扣/税收/礼券应用于产品?

JPA:处理 OptimisticLockException 的模式

如何在远程服务器上备份 MySQL 数据库?

判断Android中的应用程序数据库中是否存在列

在数据库字段中存储数字数组

Django:将博客条目查看次数加一,这有效率吗?

如何使用 Entity Framework CF 在父级之前删除子实体?

存储信用卡号 - PCI?

在 SQLite 表中使用文本作为主键不好?