zoukankan      html  css  js  c++  java
  • 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命令在瞬间删除某个月份的全部数据。

    我们需要注意的是在创建局部唯一索引时,索引字段应包括分区字段,否则会创建失败。创建全局索引则没有这样的限制。

  • 相关阅读:
    CF1109D Sasha and Interesting Fact from Graph Theory 组合数
    和与或 数位dp
    G
    E. String Multiplication dp
    Obtain a Permutation 乱搞
    CF1061E Politics 费用流
    mysql连接报错
    编译安装nginx
    SQL四种语言:DDL,DML,DCL,TCL
    Linux 常用管理命令
  • 原文地址:https://www.cnblogs.com/jjj250/p/10446120.html
Copyright © 2011-2022 走看看