验证Oracle处理速度
(这是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处理速度的更多相关文章
- 触发器 'SA.U_USER_INFO_TRG' 无效且未通过重新验证--Oracle序列
程序开发时报错:触发器 'SA.U_USER_INFO_TRG' 无效且未通过重新验证打开触发器的定义,执行其中的语句,发现序列 U_USER_INFO_SEQ 未定义.什么是序列呢?序列相当于sql ...
- 验证Oracle收集统计信息参数granularity数据分析的力度
最近在学习Oracle的统计信息这一块,收集统计信息的方法如下: DBMS_STATS.GATHER_TABLE_STATS ( ownname VARCHAR2, ---所有者名字 tabname ...
- Raid信息丢失数据恢复及oracle数据库恢复验证方案
早些时候,有个客户14块盘的磁盘阵列出现故障,需要恢复的数据是oracle数据库,客户在寻求数据恢复技术支持,要求我提供详细的数据恢复方案,以下是提供给客户的详细数据恢复解决方案,本方案包含Raid数 ...
- oracle dump数据库
最近正在看老白的<DBA的思想天空>,了解数据块结构,想通过dump data block验证oracle对于行尾的NULL,是不占用存储空间的. 我们先来看一下怎样dump数据块: 1. ...
- PL/SQL Developer连接本地Oracle 11g 64位数据库
转摘:http://www.cnblogs.com/ymj126/p/3712727.html 用于学习,笔记,以备后用. 1.登录PL/SQL Developer 这里省略Oracle数据库和PL/ ...
- 如何查看Oracle客户端版本
在实际工作中,总会遇到一些需要查看.验证ORACLE客户端版本的问题,因为一台服务器可能装了多个Oracle客户端版本:也有可能你需要知道安装的版本是32位还是64位的.如何查看Oracle客户端(O ...
- 安装oracle
1.安装vnc yum install tigervnc tigervnc-server 2.vncserver启动 3.安装依赖库 yum install -y compat-libstdc* ...
- PL/SQL Developer连接本地64位Oracle数据库
1.安装oracle Clinet 首先到Oracle官网上去下载一个Oracle 11g Client(我的是11g的oracle),不过需要先申请一个Oracle 帐号,才能下载. 目前下载地址: ...
- pl/sql developer 连接本地ORACLE 11g 64位数据库
1.登录PL/SQL Developer 这里省略Oracle数据库和PL/SQL Developer的安装步骤,注意在安装PL/SQL Developer软件时,不要安装在Program Files ...
随机推荐
- 【转】Spark Streaming和Kafka整合开发指南
基于Receivers的方法 这个方法使用了Receivers来接收数据.Receivers的实现使用到Kafka高层次的消费者API.对于所有的Receivers,接收到的数据将会保存在Spark ...
- 利用百度地图WEB服务APIGeoCoding API批量地址解析
Geocoding API包括地址解析和逆地址解析功能: 地理编码:即地址解析,由详细到街道的结构化地址得到百度经纬度信息,例如:“北京市海淀区中关村南大街27号”地址解析的结果是“lng:116.3 ...
- tesseract-ocr字库训练图文讲解
第一步合成图片集 你需要把使用jTessBoxEditor工具把你的训练素材及多张图片合并成一张tif格式的图片集 第二步 生成box文件 运行tesseract命令,tesseract mjorc ...
- 【转】NAS 黑群晖 配置完成(不含硬盘),NAS能做什么?
在配黑群晖前,240元入手过一个艾美佳的NAS感受了下,功能倒还合适,就是配置太老,厂家固件也停止更新了,一直不太满意. 后来经常关注NAS1,发现现在X86的NAS也很好自己DIY了,就长草了,向女 ...
- 项目常用Javascript分享,包含常用验证和Cookie操作
function IsEmail(str) { var r = /^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; if (r.test(str)) ...
- ELK日志收集分析系统配置
ELK是日志收益与分析的利器. 1.elasticsearch集群搭建 略 2.logstash日志收集 我这里的实现分如下2步,中间用redis队列做缓冲,可以有效的避免es压力过大: 1.n个ag ...
- JavaScript设计模式--桥梁模式--XHR连接队列
针对该模式的例子现在不是很理解,写下来慢慢熟悉. 们要构建一个队列,队列里存放了很多ajax请求,使用队列(queue)主要是因为要确保先加入的请求先被处理.任何时候,我们可以暂停请求.删除请求.重试 ...
- PHP中使用 $_GET 与$_POST 实现简单的前后台数据传输交互功能
在之前的学习过程中我们接触过前后台数据请求交互的方法有表单提交.AJAX请求以及Angularjs中的$http,今天我们尝试在PHP中使用 $_GET 与$_POST 实现简单的前后台数据传输交互功 ...
- Bootstrap 引用的标准模板
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- Ubuntu下使用网易云音乐
Ubuntu15真心各种崩溃啊 最后决定还是换成ubuntu14.04LTS了 在win.android平台上网易云音乐好用到爆 ubuntu下没有网易云音乐的客户端怎么能行 https://gith ...