(这是2009年写的东西了,在网上看到有人对数据库批量操作的‘速度’比较关注,于是就把这篇老文章整理了一下)

一、环境及前提

在244上(一台稍好一些的机器,做了RAID,机械硬盘,Raid几忘了),对eprk_person_flow表进行复制、更新,验证在Oracle数据库中操纵数据的各种方法的速度。共35,629,784条记录。

二、复制:直接建表

create /*+parallel*/table tt1 as select /*+parallel(pf, 4)*/ * from eprk_person_flow pf;

结果:
第一次:126.297秒,约每秒写入28.2W条数据。
第二次:149.109秒,约每秒写入23.9W条数据。

drop table tt1 purge;

三、复制:使用BULK COLLECT批量处理

create table tt1 as select * from eprk_person_flow where 1 = 2;

--   以下代码还有一个可以参考的地方:没有根据表结构声明太多的类型及变量。
declare
cursor cur_temp is
select /*+parallel(pf, 4)*/* from eprk_person_flow pf; type t_person_flow is tableof cur_temp%rowtype; -- 注意:这句很关键,直接引用上面的游标来定义类型 v_person_flow t_person_flow; begin
open cur_temp; loop
fetch cur_temp bulk collect into v_person_flow
limit 1000; forall i in 1..v_person_flow.last
insert /*+append nologging*/ into tt1 values v_person_flow(i);-- 注意:这里values后没有扩号 exit when cur_temp%notfound; end loop; closecur_temp; end; drop tablett1;

结果:

第一次:768.828秒。约每秒写入4.6W条数。

第二次:505.953秒。约每秒写入7.0W条数据。(加hint,把limit从200改为1000)如果在目标表上建立索引后再插入,哪怕只建立一个主键约束,耗时也将*2还多。

在复制数据时,DDL对比DML语句,在速度上还有很有优势的。

四、更新

直接更新10%、20%、50%、100%的数据。

/*
建表并建立索引
*/
create /*+parallel*/table tt1 as select /*+parallel(pf, 4)*/ * from eprk_person_flow pf; -- 147s alter table tt1
add constraint PK_tt1_PERSON_FLOW primary key (SERIAL_NUMBER) using index
tablespace NNC_INDEX01 pctfree 10
initrans 2
maxtrans 255 storage
(
initial 64M minextents 1
maxextents unlimited
);-- 102s create index I_TT1_PERSON_FLOW_TT on TT1 (PK_PERSON_ACCOUNT, PK_TRADETYPE)
tablespace NNC_INDEX01 pctfree 10 initrans 2
maxtrans 255 storage
(
initial 128M
minextents 1
maxextents unlimited
);-- 200s create index I_TT1_PERSON_FLOW_VN on TT1 (VOUCHER_NUMBER) tablespace NNC_INDEX01
pctfree 10 initrans 2
maxtrans 255
storage (
initial 128M minextents 1
maxextents unlimited
);-- 88s -- 更新数据(10%)
declare
i integer; -- 从tt1表中,取10%的数据
cursor cur_temp is
select serial_number from tt1
where rownum < cast((35629784 / 10) as integer);
type t_serial_number is tableof tt1.serial_number%type index by pls_integer; v_serial_number t_serial_number;
begin
open cur_temp; loop
fetch cur_temp bulk collect into v_serial_number limit 1000; forall i in 1..v_serial_number.count update /*+nologging*/ tt1
set occur_cash = 1, occur_unit = 1, cash_balance=1 , balance= 1 where serial_number = v_serial_number(i); exit when cur_temp%notfound;
end loop; closecur_temp; end;

更新10%的数据,共更新356W数据,耗时86.515秒,平均约每秒更新4.1W条。
更新20%的数据,共更新712W数据,耗时161.485秒,平均约每秒更新4 .4W条。
更新50%的数据,共更新1781W数据,耗时427.766秒,平均约每秒更新4.1W条。
更新100%的数据,共更新3562W数据,耗时1118.063秒,平均约每秒更新3.2W条。

在更新过程中,游标只读取1个字段,更新4个字段,由于该表有3个索引,虽然更新的字段都不在索引上,发现写入的数据量是读取的数据量 的20倍以上。(数据库归档日志打开)
以上只测试单表,并且顺序读取数据,然后根据唯一索引进行更新,如果有多表关联等要求,情况会更复杂。所以实际过程中,速度应该达不到4W/秒。

drop table tt1;

五、更新:使用中间表进行更新,并通过判断更新的数据量,进行对应的DDL操作。

-- 更新10%的数据。
-- 建立临时表
create global temporary table temp_tt1 as select * from tt1 where 1 = 2; -- 0.2s
-- 插入数据
insert into temp_tt1
select * from tt1
where rownum < cast((35629784 / 10) as integer);-- 12s
-- 更新临时表中的数据
update /*+parallel(temp_tt1, 4) nologging */ temp_tt1
set occur_cash = 1, occur_unit = 1, cash_balance=1 , balance= 1;-- 60s 分支一:
-- 删除源表中的数据
delete from tt1 t1 where exists (select 1 from temp_tt1 temp1 where t1.serial_number = temp1.serial_number);-- 163s
-- 把临时表中的数据插入到源表中
insert /*+parallel(tt1, 4)*/ into tt1 select /*+parallel(temp_tt1, 4)*/* from temp_tt1;--240s
分支二:
-- 使用临时表数据更新目标表
update tt1 t1 set (occur_cash, occur_unit, cash_balance, balance)
= (
select occur_cash, occur_unit, cash_balance, balance from temp_tt1 temp
where t1.serial_number = temp.serial_number
)
where exists ( select 1
from temp_tt1 temp
where t1.serial_number = temp.serial_number
);-- 约30分钟未完成,取消。
用上述方式更新时,硬盘IO没有规律,与其他方式相比,大部分时间都几乎“没有”IO,极慢。
-- 改为以下方式:
update /*+parallel(t1, 4) nologging*/ tt1 t1 set (occur_cash, occur_unit, cash_balance, balance)
= (
select /*+parallel(temp, 4)*/occur_cash, occur_unit, cash_balance, balance
from temp_tt1 temp
where t1.serial_number = temp.serial_number
)
where exists (
select /*+parallel(temp, 4)*/1
from temp_tt1 temp
where t1.serial_number = temp.serial_number
);-- 无效果,用大表(即使是临时表,本例有365W数据)更新更大的表时,直接用SQL实现在性能上是无法接受的。 commit;
drop table temp_tt1;

六、由此想到的:

create table XXX as select .. from ...比插入要快,由此,系统中的临时表如果用create替代insert的话,速度应该有提高。

数据对象的存储及使用设计,应严格根据实际的业务场景来定义,在建立诸如个人流水表之类的大表前,必须对表类型、各种存储结构及参数、是否及如何分区、索引的数量及字段(应根据实际查询要求建立索引)等进行详细的分析。

sql处理的速度还是有上限的,受制于应用环境。

另外,大数据量的处理,还是要考虑拆分为小任务、小事务进行。否则即使数据库有那么大的回滚段,一但后续出错,回滚的时间也等不起,给系统造成的压力也耗不起。

进行上述测试验证,只是好奇而已。

验证Oracle处理速度的更多相关文章

  1. 触发器 'SA.U_USER_INFO_TRG' 无效且未通过重新验证--Oracle序列

    程序开发时报错:触发器 'SA.U_USER_INFO_TRG' 无效且未通过重新验证打开触发器的定义,执行其中的语句,发现序列 U_USER_INFO_SEQ 未定义.什么是序列呢?序列相当于sql ...

  2. 验证Oracle收集统计信息参数granularity数据分析的力度

    最近在学习Oracle的统计信息这一块,收集统计信息的方法如下: DBMS_STATS.GATHER_TABLE_STATS ( ownname VARCHAR2, ---所有者名字 tabname ...

  3. Raid信息丢失数据恢复及oracle数据库恢复验证方案

    早些时候,有个客户14块盘的磁盘阵列出现故障,需要恢复的数据是oracle数据库,客户在寻求数据恢复技术支持,要求我提供详细的数据恢复方案,以下是提供给客户的详细数据恢复解决方案,本方案包含Raid数 ...

  4. oracle dump数据库

    最近正在看老白的<DBA的思想天空>,了解数据块结构,想通过dump data block验证oracle对于行尾的NULL,是不占用存储空间的. 我们先来看一下怎样dump数据块: 1. ...

  5. PL/SQL Developer连接本地Oracle 11g 64位数据库

    转摘:http://www.cnblogs.com/ymj126/p/3712727.html 用于学习,笔记,以备后用. 1.登录PL/SQL Developer 这里省略Oracle数据库和PL/ ...

  6. 如何查看Oracle客户端版本

    在实际工作中,总会遇到一些需要查看.验证ORACLE客户端版本的问题,因为一台服务器可能装了多个Oracle客户端版本:也有可能你需要知道安装的版本是32位还是64位的.如何查看Oracle客户端(O ...

  7. 安装oracle

    1.安装vnc  yum install tigervnc tigervnc-server 2.vncserver启动 3.安装依赖库 yum install -y compat-libstdc*   ...

  8. PL/SQL Developer连接本地64位Oracle数据库

    1.安装oracle Clinet 首先到Oracle官网上去下载一个Oracle 11g Client(我的是11g的oracle),不过需要先申请一个Oracle 帐号,才能下载. 目前下载地址: ...

  9. pl/sql developer 连接本地ORACLE 11g 64位数据库

    1.登录PL/SQL Developer 这里省略Oracle数据库和PL/SQL Developer的安装步骤,注意在安装PL/SQL Developer软件时,不要安装在Program Files ...

随机推荐

  1. 使用http -server 搭建本地简易文件服务器

    安装 npm install http-server -g 使用 1. cd project . 2. hs [pwd] -o, 默认是当前路径 ./ 3. 其他选项 -p Port to use ( ...

  2. PLSQL Developer 连接oracle(64)(instantclient_32)

    下载instantclient-basic-nt-11.2.0.2.0位客户端,加压后存放,如F:\instantclient_11_2 拷贝Oracle 11.2G的msvcr80.dll和tnsn ...

  3. 6656 Watching the Kangaroo

    6656 Watching the KangarooDay by day number of Kangaroos is decreasing just liketiger, whale or lion ...

  4. bzoj4236 JOIOJI hash 模拟

    JOIOJI桑是JOI君的叔叔."JOIOJI"这个名字是由"J.O.I"三个字母各两个构成的. 最近,JOIOJI桑有了一个孩子.JOIOJI桑想让自己孩子的 ...

  5. Windows下如何创建低权限进程

       1.  前言 在使用 Sysinternals 出品的 Process Explorer 过程中,对 “Run as Limited User” 功能的实现方式颇感兴趣,一番搜寻之下发现Mark ...

  6. centos crontab(定时任务) 使用

    一.介绍   crontab命令的功能是在一定的时间间隔调度一些命令的执行.当安装完成操作系统之后,默认便会启动此任务调度命令.crond命令每分锺会定期检查是否有要执行的工作,如果有要执行的工作便会 ...

  7. git仓库管理笔录

    Git是目前世界上最先进的分布式版本控制系统(没有之一). 小明做了个个人博客,放到了Git 仓库里面.第二天换了台电脑,只需要 git clone  克隆一下git 远程仓库的代码到本地即可.然后他 ...

  8. ZPL条码打印类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  9. Opencv怎么读入,显示,保存图像-OpenCV步步精深

    怎么读入图像呢? 我们用 img = cv2.imread('图像路径\原图像名称',0) 原图像名称要有后缀 .png , .jpg等等原图像带有的后缀. 这里我们着重说明一下图像路径,这个路径一定 ...

  10. 【计算机网络基础】数据交换技术和多路复用技术的正(nao)确(can)打开方式

    交换的作用   数据交换是计算机网络中两个终端进行数据传输的方式,它又可以分成两种类型:电路交换和分组交换.很显然,问题的核心在于“交换”,那么我们首先要思考的是:交换的作用是什么?   “交换”的作 ...