ORACLE数据库测试数据插入速度[z]
一,没有优化的速度:Executed in 69.436 seconds
drop table t purge;
create table t(x int);
/*清空共享池,注意在生产环境中千万不能做这步操作*/
alter system flush shared_pool;
create or replace procedure proc1
as
begin
for i in 1 .. 100000
loop
execute immediate
'insert into t values('||i||')';
commit;
end loop;
end;
/
下面查看下proc1插入100000记录的执行时间
SQL> set timing on;
SQL> exec proc1;
PL/SQL procedure successfully completed
Executed in 69.436 seconds
/*我们可以通过下面的语句查看此存储过程执行的具体步骤*/
select t.sql_text,t.sql_id,t.parse_calls,t.executions from v$sql t where sql_text like '%insert into t values%';
为了方便查看我用PL/SQL DEVELOPER 执行的上面语句,如下图:
从上面可以看出,每个语句都只是解析了一次,执行了一次,一共解析了10万次,也许你会问你上面只有7136行记录啊,你怎么说是解析了10万次呢。我可以告诉你肯定是解析了10万次,因为我的共享池空间不大,容纳不小10万条信息,根据FIFO 的原理你可以看出,现在我查出来的都是从92000多开始的SQL STATEMENT记录。我们知道这些SQL语句都是相似的没有必要解析10万次,即每一条语句都解析一次。这个PROC1 没有用绑定变量,这就是我们可以优化的地方。我们用绑定变量来重新测试下,下面的PROC2就只用解析一次就可以了,当然速度肯定会提高不少。
二,使用绑定变量优化后的速度:Executed in 26.505 seconds
drop table t purge;
create table t(x int);
/*清空共享池,注意在生产环境中千万不能做这步操作*/
alter system flush shared_pool;
create or replace procedure proc2
as
begin
for i in 1 .. 100000
loop
execute immediate
'insert into t values(:x)' using i;
commit;
end loop;
end;
/
SQL> set timing on;
SQL> exec proc2;
PL/SQL procedure successfully completed
Executed in 26.505 seconds
从上面可以看出,时间基本上减少了一半。
/*我们可以通过下面的语句查看此存储过程执行的具体步骤*/
select t.sql_text,t.sql_id,t.parse_calls,t.executions from v$sql t where sql_text like '%insert into t values%' order by 1;
从上面的执行情况可以知道,解析了一次,执行了10万次。完全符合我们的猜想,所以速度大大提升了。
execute immediate是一种动态SQL的写法,常用于表名字段名是变量,入参的情况,由于表名不知道,所以不能直接写SQL ,所以要靠动态SQL语句传人表名和字段名参数拼接成SQLSTATEMENT,有execute immediate调用执行。但是我的这个例子完全可以不需要动态的,可以用静态的写好。
三,用静态改写后的速度:Executed in 19.391 seconds
drop table t purge;
create table t(x int);
/*清空共享池,注意在生产环境中千万不能做这步操作*/
alter system flush shared_pool;
create or replace procedure proc3
as
begin
for i in 1 .. 100000
loop
insert into t values(i);
commit;
end loop;
end;
/
SQL> set timing on;
SQL> exec proc3;
PL/SQL procedure successfully completed
Executed in 19.391 seconds
从上面可以看出,proc3也实现了绑定变量,而且动态的特点是执行过程中再解析,而静态的SQL的特点是编译的过程是解析好的,所以上面的PRARSE_CALLS是0。注意这个和上面一个图比较,上面的时PARSE_CALLS 是1,而这个是0,所以静态的少了一个执行的时候的解析过程。
我们可以看出上面的三个PROC都是一条语句就commit一次,我们完全没有必要这样做,我们可以一起提交。如下例: commit的时把log_buffer里的信息通过LGWR写到online redo log里,触发LGWR写10万次,而且我们知道LGWR写的太频繁了。
四,批量提交的速度:Executed in 11.42 seconds
drop table t purge;
create table t(x int);
/*清空共享池,注意在生产环境中千万不能做这步操作*/
alter system flush shared_pool;
create or replace procedure proc4
as
begin
for i in 1 .. 100000
loop
insert into t values(i);
end loop;
commit;
end;
/
SQL> set timing on;
SQL> exec proc4;
PL/SQL procedure successfully completed
Executed in 11.42 seconds
可以看出我们用的时间更少了。
五,集合写法的速度:Executed in 0.452 seconds
drop table t purge;
create table t(x int);
/*清空共享池,注意在生产环境中千万不能做这步操作*/
alter system flush shared_pool;
/*下面的语句是由上面的一条一条的插入改为一整批的写进data buffer区里,所以比上面的快,批处理肯定比一个一个的执行快*/
insert into t select rownum from dual connect by level<=100000;
SQL> set timing on;
SQL> insert into t select rownum from dual connect by level<=100000;
100000 rows inserted
Executed in 0.452 seconds
这个是上面的前四种都是一条一条的插入的,我这个集合写法是一整批地写进到DATA BUFFER里,所以比上面的四种情况要快的多。
六,用直接路径写法速度(100万条记录):Executed in 1.514 seconds
/*下面用直接路径的方式来操作,速度会比上面更快,所谓直接路径就是数据不经过database buffer,而是直接写到磁盘,少了一步写到数据缓冲区(database buffer)的动作*/
drop table t purge;
alter system flush shared_pool;
SQL> set timing on;
SQL> create table t as select rownum x from dual connect by level<=1000000;
Table created
Executed in 1.514 seconds
注意此时我插入的记录数十上面的10倍,我是插入100万条记录只用了1.514 seconds.
注意:直接路径的写法比集合写法快事因为,insert into select .... 的方式是将数据首先写到data buffer里,然后再刷到磁盘里。而create as t 的方式跳过了数据缓冲区(data buffer), 直接写进磁盘中,这种方式称之为直接路径读写方式。本来是先到内存,在到磁盘,更改为直接到磁盘,少了一个步骤,所以速度快了。
七,并行写法的速度(100万条记录):Executed in 0.733 seconds
/*并行加直接路径,而且是不写日志的,所以速度比上面的更快*/
drop table t purge;
alter system flush shared_pool;
set timing on;
create table t nologging parallel 64 as select rownum x from dual connect by level<=100000;
SQL> set timing on;
SQL> create table t nologging parallel 4 as select rownum x from dual connect by level<=1000000;
Table created
Executed in 0.733 seconds
我上面只用了parallel 4,如果更多的话,还会更快!!!
[z]
三个提高Oracle处理大量数据效率的有效途径
Oracle性能话题涉及面非常广,市场上有很多书籍专门介绍Oracle调优。对性能的追求是无止境的,需要长期不懈的努力;但要避免性能成为问题却不难,甚至可以说很简单。本文从简单实用的角度出发,给出几个提高Oracle处理大量数据效率的有效途径。
一、配置数据库初始化参数
数据库的全部初始化参数可以在OEM中看到。参见下图:
在新建一数据库时,如果不配置这些初始化参数,Oracle会给这些参数以默认值。当数据库规模不大时,采用Oracle的默认值通常不会遇到性能问题。下面介绍对处理大量数据效率有“举足轻重”影响,并且,默认值会带来性能问题的几个参数:
1) db_block_size
该参数设置了Oracle进行一次I/O的基本单位——数据库块的大小 (以字节计)。毫不夸张的说,该参数对于大数据量处理是最重要的一个参数。该参数值设置的越大,对大数据量处理越有利。受操作系统所限,NT4最大只能设置为8K,Win2k最大只能设置为16K。Oracle本身允许的最大值是64K。忘了说了,db_block_size应设置为2的幂。
对于分析型数据库,设置为32K是不错的选择。对于OLTP系统,笔者没有多少经验,网上的说法是设置8K是个比较好的平衡点。Oracle是有许多“神话”的,8K的说法未必符合现在的软硬件情况,更未必符合我们企业的实际情况。如果有时间有机会,比较一下8K好还是16K好总是不会错的。
db_block_size是最基本的一个参数,也是最容易被忽视的一个参数。该参数只能在创建数据库时设置,此后不能更改;一旦有所失误,只能通过重建数据库的方法补救。因此,您建库时应当慎重考虑该参数。
2)
db_file_multiblock_read_count
Oracle官方的说明:在涉及一个完全连续扫描的一次 I/O 操作过程中读取的块的最大数量。对于大的查询来说,进行全表扫描往往比使用索引效率高很多。全表扫描操作是典型的“完全连续扫描”。如果db_block_size设置为32K,db_file_multiblock_read_count设置为8;则一次I/O操作最多可以连续读8个数据库块,即256K。
db_file_multiblock_read_count并非越大越好。对于数据分析系统,db_file_multiblock_read_count和db_block_size的乘积为256K足够了。对于建立在Unix上的OLTP系统,根据网上的说法,二者的乘积为64K是不错的选择。
根据笔者的经验,让数据连续分布在物理磁盘上比考量该参数更加有效。
3) sort_area_size
sort_area_size的重要性可以说是和db_block_size并列的。该参数指出数据库执行一个查询时最多可以使用多大内存来排序。受系统资源所限,我们无法将该参数设置太大。特别是当我们采用独立模式建库时,每个Session都可能会申请一个或多个排序空间。如果我们设置sort_area_size为8M,同时登上来100个用户并发查询,则可能会占去800M内存甚至更多。当主存不够用时,就要用虚拟内存了。如果Oracle被迫使用虚拟内存,则数据库的性能将急剧下降。
对于该参数的设置,网上有人建议至少应超过用于排序记录数的平方根。也就是说,对100万条记录进行排序,每条记录占用1K空间,则sort_area_size至少应设置为1M。对1000万条记录进行排序,每条记录占用1K空间,sort_area_size设置为4M应该够用了。
根据上述数字,OLTP系统的sort_area_size不妨设置为1M或2M;数据分析系统的sort_area_size不妨设置为4M或8M。
db_file_multiblock_read_count和sort_area_size在数据库建立好以后是可以修改的。修改方法很简单。搜索Oracle的安装目录,找到PFILE文件夹(可能会找到多个,其父目录的名字会给我们提示),里面有一个init文本文件,照着里面的内容修改就可以了(找不到相关参数就自己加一个)。修改完毕后重启数据库方能生效。Oracle9i以上版本可以做到不用重启数据库,本文就不介绍了。
二、编写高效的SQL
一般说来,看起来简单的SQL通常都不会遇到性能问题。SQL的执行效率通常比程序的执行效率要高。因此,尽量用SQL解决问题和尽量用简单的SQL解决问题应当是我们开发的指导原则。
编写高效的SQL需要一定的基本功。本文不讨论SQL的理论基础。本文仅介绍一个有用的技术:人为干预SQL的执行计划。当SQL较复杂时,执行计划的可能性会非常多。用最短的时间选择一个最优的执行计划是Oracle奋斗的目标。Oracle数据库有相关的参数来调整挑选执行计划的算法,这些参数本文不讨论,有兴趣的读者可以自己上网去搜。
所谓“人为干预SQL的执行计划”实际上是提示Oracle如何去挑选最优的执行计划。SQL提示的语法很简单:用“/*+”和“*/”将提示包括起来,中间写上关键字就可以了。SQL:提示的关键字有很多,下面介绍几个典型的关键字,更多的用法可以自己上网搜。
1)指定全表扫描:
SELECT /*+FULL(table_name)*/ field1,field2
FROM table_name;
一个大查询如果用到了一个大表中相当一部分的数据,则采用全表扫描的执行计划会比采用索引的执行计划效率高很多。
2)数据直接插入到表的最后,可以提高速度:
INSERT /*+append*/
INTO table_name
select * from table_name1;
Oracle中很多数据块因为曾经做过delete操作而有空闲空间,如果使用append关键字,则Oracle不会去寻找这些有空闲空间的数据块,从而提高了insert语句的执行速度。需注意append关键字只适合于大数据量插入。
三、分区
分区技术相对前面介绍的技术而言要复杂一些。分区实际上是据根据某(些)个字段在物理上将一个大表的数据分开存储,从而,能提高我们查询的效率,同时也能加强我们对数据的管理。典型例子的是根据日期字段分区,从而,当我们查询某个时期的数据时,只需要扫描某个分区的数据而不需要扫描整表的数据。
当我们决定采用分区技术时,只需要在create table语句以及create index语句中增加一些语法。一般的面向DBA的书籍都会有专门的章节介绍分区技术。这里不再赘述。
一个表是否被分区并不影响我们使用:对普通表的操作可以用在分区表上。相反,分区表增加了我们使用该表的灵活性,创建分区表后,我们可以使用Alter table命令来增加、删除、交换、移动、修改、重命名、划分、截断一个已存在分区的结构。一个典型的例子,如果用月份分区,我们可以使用truncate命令在瞬间删除某个月份的全部数据。
我们需要注意的是在创建局部唯一索引时,索引字段应包括分区字段,否则会创建失败。创建全局索引则没有这样的限制。
ORACLE数据库测试数据插入速度[z]的更多相关文章
- 向Oracle数据库中插入数据出错:ORA-01036 无效的变量名或数据
向Oracle数据库中插入数据出错: 经过排查,因为Update数据时没有出错,所以OracleHelper没有问题: 看异常信息提示:无效的变量和数据,应该是SQL语句的问题,调试时所传的实例Use ...
- Oracle数据库中插入日期型数据(to_date的用法)(转载)
往Oracle数据库中插入日期型数据(to_date的用法) INSERT INTO FLOOR VALUES ( to_date ( '2007-12-20 18:31:34' , 'YYY ...
- SQL语句往Oracle数据库中插入日期型数据(to_date的用法)
Oracle 在操作数据库上相比于其他的 T-sql 有微小的差别,但是在插入时间类型的数据是必须要注意他的 to_date 方法,具体的情况如下: --SQL语句往Oracle数据库中插入日期型数据 ...
- 解决getJdbcTemplate往oracle数据库中插入数据返回主键出错问题
我们使用Spring中的JdbcDaoSupport往Mysql中插入数据并返回主键代码,我们使用的mysql数据库,主键在数据库中设置为自增长:该类继承自JdbcDaoSupport,所以能直接使用 ...
- 客户Oracle数据库在插入数据的时候报超出最大长度的错误(规避风险)
背景: 项目使用oracle数据,在开发环境测试一些正常.项目部署到客户的服务器上后,系统在添加数据的时候报错.输出错误信息,发现是“超出最大长度”的异常. 但是按照数据库的设计,添加的数据应该在允许 ...
- 003杰信-在jsp页面输入数据,然后在oracle数据库中插入factory数据,当字段允许为空时要特殊处理
本博客的内容全部来自于传智播客,特在此说明. 业务要求如下:在jsp页面(jFactoryCreate.jsp)上输入数据时,转到后台,并输入到数据库. jFactoryCreate.jsp页面:
- java向oracle数据库中插入当前时间
public class Test{public static void main (String args []){ java.util.Date a = new java.util.Date(); ...
- Mybatis在oracle数据库中插入数据后返回自增值ID
1.将id设置成自增序列 CREATE OR REPLACE TRIGGER "DATALIB"."TRIG_USER_ADD" BEFORE INSERT O ...
- Oracle数据库mybatis 插入空值时报错(with JdbcType OTHER)
参考文档: 1.https://blog.csdn.net/fishernemo/article/details/27649233 2.http://helgaxu.iteye.com/blog/21 ...
随机推荐
- JS笔记汇总
注释必须要多写! 1.方便后台看 2.方便自己查错和优化 事先先沟通约定好,比如交互的数据格式需求是怎么样的啊,功能模块的逻辑是怎么样的等等.提前先和产品还有后台沟通好. JSON内不能包含注 ...
- springboot解决跨域问题
在启动类里加入corsFilter import org.springframework.boot.SpringApplication; import org.springframework.boot ...
- 命令:jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
命令:jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令 这些命令 必须 在 linux jdk bin 路径 下执行 eq: ./jstack 10303 即可 如果想把 ...
- 记一次nginx403错误
同事开发微信小程序,小程序通过API接口调用我们的人脸比对API,但是一直是提示403,通过查看查看nginx日志,发现请求并没有转发出去,转发出去的请求,应该是301,重定向, 然后就开始在ngin ...
- FluentData -Micro ORM with a fluent API that makes it simple to query a database 【MYSQL】
官方地址:http://fluentdata.codeplex.com/documentation MYSQL: MySQL through the MySQL Connector .NET driv ...
- 【java】之cron表达式
秒(~) 分钟(~) 小时(~) 天(月)(~,但是你需要考虑你月的天数) 月(~) 天(星期)(~ =SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) .年份(-) 其中每个元素 ...
- easyui layout布局的属性说明
layout布局的属性说明: 名称 类型 描述 默认值 fit boolean 当设置为 true 时,就设置布局(layout)的尺寸适应它的父容器.当在 'body' 标签上创建布局(layout ...
- [编程小技巧]Notepad++中如何实现文本对比功能?
1.打开Notepad++插件中心 2.安装Compare 3.按提示重启Notepad++ 4.点击Compare比较临近的两个文件 5. 取消比较 6 Comp ...
- Python第2天
今天学习的主要内容: pycharm专业版的安装和注册,采用注册码的方式注册. 运算符,+ — * / // % < > <= >= != <> . 基本数据类型 ...
- leetcode98
class Solution { public: vector<int> V; void postTree(TreeNode* node) { if (node != NULL) { if ...