第七章:数据库调优艺术

点击数:2024发布日期:2020-04-19 14:44:51 来源:oracle实战与提高

第七章:数据库调优艺术

    数据库的性能至关重要。在你看不见想不到的时候,在你看不见想不到的地方,速度就影响了生产效率。在速度慢的时候,必须有性能优化的意识,不能一味的增加硬件。128GB内存,128颗CPU不一定使得上。常常见到96GB内存,使用了6GB,只用了一个零头,白白浪费了硬件,硬件不会自动用上,需要我们调整。

    曾经见过一个客户,由于性能慢,使用系统的客户端部门和管理运维的部门吵起来了,不可开交。花点钱做个调优不就完了嘛,由于甲方流程原因根本走不动调优这条路,我只能感到惋惜和遗憾了。这么好的机器,这么慢的速度,可惜。

7.1背景

    随着单位业务的发展,数据库的数据量呈线性增长。系统所承受的压力越来越大。运行几个月或几年,数据库系统很容易出现性能问题,可能会导致前台响应变慢,业务处理时间变长,CPU瓶颈突出,内存不足,I/O瓶颈等问题。特别是在业务高峰期。针对这些问题,我们要对数据库系统进行整体优化,优化方面包括应用程序,数据库,主机和存储。为了更好地完成数据库系统的优化,我们将对系统进行多次的性能评估,收集相关的信息,然后对收集的信息进行评估,提出我们的解决方案。

        数据库调优是一门艺术。调整完成之后,可以让数据库看起来更完美,用起来没有最快只有更快。

    有些问题是一开始安装的时候,就没有安装好,参数也没有设置好。我们做调优的时候,尽可能的一并把这些问题解决掉。如果由于种种原因做不了的,也尽量让它的影响降到最低。最大限度的追求完美。做不了的,虽留有遗憾,也瑕不掩瑜。最后带给客户的是没有最快只有更快。

7.2收集和了解哪些信息

    数据库存在性能问题,我们就要寻找性能瓶颈,瓶颈一般又不是一个,需要从各个方面加以考虑。以下是我们需要了解的一些信息,有了这些信息,我们就可以知道调优从什么地方着手了。当然探寻这些问题的答案最好是调优工程师亲自登录系统去看,如果光远程传一个日志报告之类的,效率低下不说,调优工程师也很难了解的很全面。除非是断判一个问题,只从AWR报告或执行计划中就可以大概的判定,整体的调优,肯定是要现场操作。

1、数据库的AWR报告,ASH报告。

2、操作系统的CPU利用率,内存使用率,I/O响应时间I/O等待情况。

3、数据库版本。PSU, CPU补丁情况。

4、数据库参数,包括隐含参数;操作系统参数。

5、日志的组数,member组员的大小,日志的写速度。

6、高峰时间段的警告日志,相对应的trace文件。

7、硬件资源是否充足,是否需要扩展,如增加内存。

8、数据库OLTP的整体响应时间;报表批处理的响应时间。

9、客户端期望的数据库响应时间;某个业务以前的响应时间。

10、响应慢的应用主要等待时间耗在什么事件上?

11、由于长年累积,数据段中的数据是否需要整理碎片,如表和索引的整理。

12、内存充足的情况下,为了减少I/O等待,可以将表和常用的程序包keep到内存里。

13、对于大表大索引绑定变量等问题,是否可以联合发开商进行操作?

14、历史数据是否可以迁入历史库,减少核心库压力。

15、Oracle的自动任务?如审计,统计信息,直方图,auto space advisor,auto sql tuning等。

16、哪些SQL或程序运行较慢。SQL是否有调优的空间。

17、是否存在内存锁的争用?如gc开头的等待事件,latch free, library cache等。

18、热块问题。

19、网络速度。


7.3调优的依据和手段

    为了把调优的手段介绍的更加全面,我们假设我们的数据库存在各种问题,都需要一一调整,目的是根据我们的判断,介绍更多的解决问题的方法。


    redo调整。

    增加redo日志组数,将redo由RAID5移至RAID10,将member大小由50MB扩至200MB。

判断的依据:

Top 5 Timed Events

~~~~~~~~~~~~~~~~~~                                                     % Total

Event                                               Waits    Time (s) Ela Time

-------------------------------------------- ------------ ----------- --------

CPU time                                                       94,674    39.25

db file sequential read                         6,098,736      65,327    27.08

log file sync                                   1,293,986      43,891    18.20

db file scattered read                          2,092,560      24,769    10.27

buffer busy waits                                 840,944       6,457     2.68

          -------------------------------------------------------------


Wait Events for DB: YSDB  Instance: ysdb  Snaps: 20064 -20065

-> s  - second

-> cs - centisecond -     100th of a second

-> ms - millisecond -    1000th of a second

-> us - microsecond - 1000000th of a second

-> ordered by wait time desc, waits desc (idle events last)

                                                                   Avg

                                                     Total Wait   wait    Waits

Event                               Waits   Timeouts   Time (s)   (ms)     /txn

---------------------------- ------------ ---------- ---------- ------ --------

db file sequential read         6,098,736          0     65,327     11      4.0

log file sync                   1,293,986      1,065     43,891     34      0.9


说明:1、log file sync等待事件已经进入top5,证明我们的redo写存在速度问题;

2、log file sync的等待时间,一小时的快照间隔,它总共等待了43,891秒钟,12.2小时,总的等待时间也是蛮长的,是一个可以提高速度的部分。

3、再看平均等待时间log file sync,平均等待时间为34ms,而Oracle建议log file sync的平均等待时间不宜超过5ms,由此大致的可以推断,我们的redo日志是放在了RAID5上。建议调整到RAID1上。

4、警告日志和redo相关的

Fri May 19 09:07:49 2015

Thread 1 cannot allocate new log, sequence 117398

Checkpoint not complete

... ...

Fri May 19 10:12:32 2015
Thread 1 cannot allocate new log, sequence 117421
Checkpoint not complete

    警告日志报不能分配新的redo日志,检查点没有完成。也是由于磁盘的速度不好,redo日志太小,日志组数不够三个方面可能都有责任。

5、看一下v$log

SQL> select group#,thread#,bytes,members,status from v$log;


    GROUP#    THREAD#      BYTES    MEMBERS STATUS

---------- ---------- ---------- ---------- ------------------------------------------------

         1          1   52428800          2 ACTIVE

         2          1   52428800          2 ACTIVE

         3          1   52428800          2 CURRENT

说明,由于I/O速度慢,单位时间redo写的多,致redo状态处于active。如果底层做了RAID,这里也没有必要使用两个member了。如果使用两个member,必须把两个member分别放在不同的磁盘上。放在一个磁盘上,同时写,这不是给磁盘增加压力吗?况且要坏都坏。如果非要防止人为删除,应该把两个member放在不同的挂载点下,不同的文件夹里。

    以上的种种迹象表明,我们的redo需要调整。调至最优的方案是1、将redo挪至15000转的磁盘做的RAID1上去。2、将日志组数增加至6组。3、将redo大小改为一个400MB。然后再执行以上的检查。

    调整的方法如下:

增加三个日志组至新的挂载点/ora_redo,这个挂载点是我们在存储上新划的RAID1磁盘。

SQL> alter database add logfile group 4 '/ora_redo/redo04.log' size 400m;

Database altered.

SQL> alter database add logfile group 5 '/ora_redo/redo05.log' size 400m;

Database altered.

SQL> alter database add logfile group 6 '/ora_redo/redo06.log' size 400m;

Database altered.


将当前的日志切换到4,5,6上的任意一个,然后稍等几分钟,等第1,2,3组日志不活动了,将1,2,3删除。

SQL> alter system switch logfile;

System altered.

SQL> /

System altered.

SQL> alter database drop logfile group 1;

Database altered.

SQL> alter database drop logfile group 2;

Database altered.

SQL> alter database drop logfile group 3;

Database altered.


1,2,3组日志删除完成之后,再添加新的1,2,3组至/ora_redo.

alter database add logfile group 1 '/ora_redo/redo01.log' size 400m;

alter database add logfile group 2 '/ora_redo/redo02.log' size 400m;

alter database add logfile group 3 '/ora_redo/redo03.log' size 400m;


    新的日志添加完成后,将旧的1,2,3组日志在物理上使用rm删除。

[oracle@yingshu ysdb]$ pwd

/u01/app/oracle/oradata/ysdb

[oracle@yingshu ysdb]$ rm -r redo*


    至此我们的redo调整就完成了。我们重新查看新成生的AWR报告,再观察相应的等待事件,肯定有了很大的改观。警告日志也不再报无法分配新的redo了。


    AIX5L6.1操作系统参数调整。

    运行在IBM aix上的Oracle数据库调优过程中,相关的操作系统参数,主要有以下几个需要关注。如果我们的生产库为AIX请关注以下几个参数。我这里直接给出了调整的命令,然后重新启动主机使参数生效。作用是让操作系统文件型内存使用的内存限制在30%以下,让更多的内存留给Oracle用做ASM、裸设备、SGA,如果客户用的是文件系统,则以下的值则不适用。需要另行评估计算参数的新值。

vmo -p -o maxclient%=30

vmo -p -o maxperm%=30

vmo -p -o minperm%=5

vmo -p -o strict_maxperm=1


    linux操作系统参数调整。

kernel.shmmax参数:Linux进程可以分配的单独共享内存段的最大值。一般情况下,该值应该大于SGA_MAX_TARGET或MEMORY_MAX_TARGET的值。如果主机上只运行一个实例,则可以设置为总内存大小的65%。数据库占用的总内存大小也为60左右。

kernel.shmmni参数:设置系统级最大共享内存段的数量。Oracle推荐值为4096。

kernel.shmall参数:设置共享内存的总页数,算法为总的物理内存大小除以一个分页的大小,这个值太小有可能导致数据库启动报错。分页大小由命令getconf PAGE_SIZE获取。对于主机内存为96G的情况,该值的计算方法是:

[root@yingshu ~]# getconf PAGE_SIZE

4096

SQL> select 96*1024*1024*1024/4096 from dual;

96*1024*1024*1024/4096

----------------------

              25165824

semaphores信号量是用来调协进程对共享资源的访问的,进程间访问共享内存时提供同步。

semmsl参数:每个信号量组中信号量最大数量,推荐的最小值是250。对于系统中存在大量并发连接的系统,推荐将这个值设置为PROCESSES初始化参数加10。

semmni参数:系统中信号量组的最大数量。Oracle10g和11g的推荐值为142。

semmns参数:系统中信号量的最大数量。semmns的值不能超过semmsl*semmni,超过了semmsl*semmni是非法的,因此推荐semmns的值就设置为semmsl*semmni。oracle推荐semmns的设置不小于32000,假如数据库的processes参数设置为1500,则semmns的设置应为:

select (1500+10)*142 from dual;

(1500+10)*142

-------------

       214420

semopm参数:每次系统调用可以同时执行的最大信号量的数量。因为一个信号量组最大拥有semmsl个,因此可以将semopm设置为semmsl的值。Oracle验证的10g和11g的semopm的配置为100。

修改以上参数的方法,可以用vi编辑器编辑/etc/sysctl.conf这个文件,然后使用sysctl -p命令使其生效。


    数据库参数调整。

    从Oracle10g开始,内存可以自动管理了,ASMM即(Automatic Shared Memory Management),我们只需要设一个sga_target,sga_max_size或memory_target,memory_max_target就不用管下面各个池的大小了。但是,自动管理内存好吗?事实证明,内存自动管理在数据库压力比较大的情况下,会使分配给某个池的内存一会大一会小,容易出事。所以我是不建议大家用内存自动管理,还是手工管理内存来的稳定。

    Oracle10g内存自动管理还受statistics_level参数的影响,该参数必须设置为typical或all,内存自动管理才生效,如果此参数的值是basic,则内存自动管理无效。

    Oracle10g内存自动管理可以管理5个内存池的大小,它们是:buffer cache、shared pool、large pool、java pool和stream pool。其它的内存参数仍然需要手工设置。视图v$sga_dynamic_components记录了可以动态调整的内存的大小。通过这个视图可以查询当前的自动设置的值。

    内存自动管理受后台进程MMAN(Memory Manager)的控制。由此后台进程进行内存建议的收集,收集来建议之后,也是由此进程自动调置对应的参数。它设置的参数都是以两个下划线开始,如"__shared_pool_size",是自动调整的参数。数据库启动时,会比较dba设置的参数和自动调整的参数,shared_pool_size设置的比"__shared_pool_size"大,则用shared_pool_size,否则用"__shared_pool_size"。

    我的习惯是不用内存自动管理,建库的时候就不用内存自动管理建,使用手工设置内存的大小,省的内存自动管理在以后的运行中出故障。如果目前数据库内存为自动管理,我们也建议改为手工管理,下面介绍一下内存自动管理改为手工管理的方法。

    为了避免修改的过程中出现错误致数据库起不来,我们先备份一下当前的spfile。拷贝也行,创建一个pfile到某个目录下也行。

SQL> create pfile='/tmp/pfile20150512' from spfile;

File created.


    主机的总内存是160GB,我们设置的各个内存池的大小,都跟总内存有关系,可以根据自身的情况再做一下大小的微调,总的比例应该是在sgadb_cache_size用于缓存数据的内存区域最大,用于存放数据字典和SQL语句的shared_pool_size内存区域第二大。如果此主机上只运行一个实例,那么sga占主机总内存的60%左右。

alter system set sga_max_size=120g scope=spfile sid='*';

alter system set sga_target=0 scope=spfile sid='*';

alter system set db_cache_size=80g scope=spfile sid='*';

alter system set shared_pool_size=10g scope=spfile sid='*';

alter system set java_pool_size=120m scope=spfile sid='*';

alter system set large_pool_size=500m scope=spfile sid='*';

alter system set log_buffer=79193088  scope=spfile sid='*';

alter system set pga_aggregate_target=32g scope=spfile sid='*';


    将常用的应用程序包keep到内存中。

    对于频繁使用的数据库对象而言,如存储过程,触发器,序列,游标等,将其keep到内存中,可以减少物理I/O提高用户的响应时间。keep的过程需要一个软件包dbms_shared_pool,这个软件包在Oracle 11g中不是被默认创建的,需要执行dbmspool.sql来创建。有了dbms_shared_pool这个包之后,用户就可以将自己常用的程序keep到内存中了。

    我们可以先从v$db_object_cache,v$sqlarea里将执行次数多的程序包查询出来。然后根据结果判断,哪些包是我们最常用的,是需要keep的。被经常使用的程序名用下面的语句查询,其中执行的次数,和包占用内存的大小可以做适量的调整。

select a.owner,                                     //对象的owner

  a.name,                                         //对象的名称

  a.sharable_mem,                                 //共享内存占用大小

  a.kept,                                         //是否被keep在内存中

  a.executions ,                                  //执行的次数

  b.address,                                      //语句的地址

  b.hash_value                                    //hash

  from v$db_object_cache a,

  v$sqlarea b

  where a.kept = 'NO' and

  (( a.executions > 1000                          //执行次数

  and a.sharable_mem > 50000)                     //共享内存占用大小

  or a.executions > 10000)                       //执行次数

  and substr(b.sql_text,1,50) = substr(a.name,1,50);


    如果了解我们的应用程序,知道哪个用户下的哪些包会被经常使用,也可以通过用户名,程序名确定我们要keep的内容。用的视图就是dba_objects。

select object_name,object_type from dba_objects where owner='YS';

   

    keep对象之前我们先使用dbmspool.sql创建一下dbms_shared_pool包。使用sys用户以dba身份执行。 

SQL> @?/rdbms/admin/dbmspool.sql

Package created.

Grant succeeded.


    创建完成了之后,我们就可以把常用的程序包放在内存里了。比如通过上面的查询判断,我们得出以下的操作系统包被经常使用,这些包属于sys用户,用的很频繁,就可以用下面的命令将它们keep到内存中。如果是应用用户的程序,keep的方法也一样。

exec dbms_shared_pool.keep('STANDARD');

exec dbms_shared_pool.keep('DBMS_SYS_SQL');

exec dbms_shared_pool.keep('DBMS_SQL');

exec dbms_shared_pool.keep('DBMS_UTILITY');

exec dbms_shared_pool.keep('DBMS_DESCRIBE');

exec dbms_shared_pool.keep('DBMS_JOB');

exec dbms_shared_pool.keep('DBMS_STANDARD');

exec dbms_shared_pool.keep('DBMS_OUTPUT');

exec dbms_shared_pool.keep('DIANA');

exec dbms_shared_pool.keep('PIDL');


    将常用的小表Keep到内存中

    我们的应用开发商应该知道哪些表比较常用;通过AWR报告里的物理读(Segments by Physical Reads),也可以得知哪些段比较消耗物理I/O;我们可以通过dba_segments查询到这个表有多大。如果大小合适,内存足够放的下,这时,如果I/O又成为我们性能的瓶颈,我们就可以把对应的表keep到内存中来。一旦实现keep,省去了I/O的时间,我们的SQL执行速度将明显提升。就算存储的性能不好,也没有关系,因为除第一次读取,我们这些表从此不在存储里读取了。

... ...

Segments by Physical Reads          DB/Inst: YSDB/ysdb      Snaps: 10762-10763

-> Total Physical Reads:             1,572,493

-> Captured Segments account for    38.9% of Total


           Tablespace                      Subobject  Obj.      Physical

Owner         Name    Object Name            Name     Type         Reads  %Total

---------- ---------- -------------------- ---------- ----- ------------ -------

YS         YS_DATA01  YS_KUCUNZ                       TABLE          114   35.74

YS         YS_INDEX01 IDX_CAIWUZ                      INDEX            6    1.88

YS         YS_INDEX01 PK_YS_RENINFO                   INDEX            2     .63

YS         YS_INDEX01 IDX_RENINFO_PWD                 INDEX            1     .31

SYS        SYSAUX     WRI$_ADV_OBJECTS                TABLE            1     .31

          -------------------------------------------------------------

... ...

上面的AWR报告显示,表YS.YS_KUCUNZ占用的I/O最大,物理读最频繁。

我们查看一下它有多大?

SQL> col segment_name for a15

SQL> col segment_type for a15

SQL> select owner,segment_name,segment_type,bytes/1024/1024 from dba_segments where segment_name=' YS_KUCUNZ ';

OWNER                SEGMENT_NAME    SEGMENT_TYPE    BYTES/1024/1024

-------------------- --------------- --------------- ---------------

YS                   YS_KUCUNZ           TABLE               80.0625

ys.ys_kucunz这张表有80MB,不算太大,可以将它keep到内存中。keep表的语句如下:

SQL> alter table ys.kucunz storage(buffer_pool keep);

Table altered.

    如果还有其它的表需要常驻内存,方法和上述的一样。



    大表重组

    日积月累的表的碎片,也是我们要调整的对象。经过几年的增删改操作,表里已经积累的大量的碎片。查看表的碎片之前,我们先收集一下表的统计信息,统计信息不准确,我们查的碎片程度也不准确。

SQL> exec dbms_stats.gather_table_stats(ownname=>'SHU',tabname=> 'STUD');

PL/SQL procedure successfully completed.


可以用以下的语句来查询表的碎片程度。浪费空间比较多的表,就是我们要重组的重点了。

select table_name,                                              //表名

round((blocks * 8), 4) "highwm_k",                              //高水位线占用的大小

round((num_rows * avg_row_len / 1024), 4) "real_use_k",         //真实的大小

round((blocks * 10 / 100) * 8, 4) "free_spc_(pctfree) k",       //有多少预留空间

round((blocks * 8 - (num_rows * avg_row_len / 1024) - blocks * 8 * 10 / 100), 4) "waste_k"

from dba_tables                                                 //(上一行)浪费的空间

where table_name = 'STUD';                                      //想了解碎片的表名

TABLE   HighWM_k Real_Use_k Free_Spc_(Pctfree) k    Waste_k

----- ---------- ---------- -------------------- ----------

STUD       11024          0               1102.4     9921.6



对于数据变化量比较大的表,我们可以对其进行重组。重组的方法有多种。

1、expdp导出来,将原表删除,impdp再导进去,实现了对表碎片的整理。这种办法做数据备份迁移的时候常用,整理碎片一般不用这个方法。

2、create table TEACH2 as select * from teach;这种方法也不怎么常用,因为它生成一个新表,还要修改表名,又不能将表中的默认值插到新表里去,用的时候需要谨慎。

3、第三种方法是move表,就是我们最常用的方式,执行的时间一定是在业务不忙的时候,保证表空间的剩余空间,要比此表大。如果表空间没有剩余空间,可以将表move到其它表空间,再move回来。对于特别大的表或分区,一定要计算出大概的move时间,在规定的停业务时间必须完成操作,不能因为move时间过长,影响了营业。注意:move表之后,此表上面所有的索引都将失效,需要重建所有此表上的索引。

SQL> alter table ys.teach move;

Table altered.


将表move至其它表空间,再move回来。

SQL> alter table ys.teach move tablespace users;

Table altered.

SQL> alter table ys.teach move tablespace ystbs;

Table altered.


如果是move分区表,需要一个分区一个分区的做。

SQL> alter table ys.stud move partition part_001;

Table altered.

SQL> alter table ys.stud move partition part_002;

Table altered.


  shrink table

4、在Oracle10开始,又推出了一种新的整理表碎片的方法,就是shrink收缩。这个功能必须打开行移动,有三个不同的选项表示三种不同的整理级别。shrink不需要重建索引,是比move进步的一点,但shrink会改变数据的rowid,如果应用在使用的过程中调用了rowid,那么就不能用shrink了,使用LOGMINER恢复过程中也会用到rowid,看来shrink还会影响LOGMINER,但以上两种假设在我们的实际生产中很少用到,shrink还是可以用的。

打开行移动

SQL> show user

USER is "SHU"

SQL> alter table stud enable row movement;

Table altered.


收缩表之前先收集一下表的统计信息。统计信息里有表的高水位线,我们在查询高水位线之前必须先收集统计信息,否则,我们的高水位线有可能是不准确的。

SQL> exec dbms_stats.gather_table_stats(ownname=>'SHU',tabname=> 'STUD');

PL/SQL procedure successfully completed.


我们先了解一下High Water Mark的计算方法,高水位线的概念。

查询表的高水位线。

SQL> select blocks, empty_blocks,num_rows from dba_tables where table_name='STUD' and owner='SHU';

    BLOCKS EMPTY_BLOCKS   NUM_ROWS

---------- ------------ ----------

       370            0     100000

结果显示,表里没有空块,这个表不需要我们整理。


为了达成我们的实验环境,我们将表里的数据删除一半。

SQL> delete from stud where studid<=50000;

50000 rows deleted.


查询在高水位线以下,有多少MB空闲空间。

select table_name,

 (blocks * 8192 / 1024 / 1024) -

 (num_rows * avg_row_len/ 1024 / 1024) "data lower than hwm in mb"

 from user_tables

 where table_name = 'STUD';

TABLE_NAME               Data lower than HWM in MB

----------------------- -------------------------

STUD                     2.17536926


SQL> alter table stud shrink space compact;

Table altered.

收缩表,但高水位线保留。


SQL> select blocks, empty_blocks,num_rows from dba_tables where table_name='STUD' and owner='SHU';

Used Blocks EMPTY_BLOCKS   NUM_ROWS

----------- ------------ ----------

        370            0      50000

高水位线并没有降低。


SQL> alter table stud shrink space;

Table altered.

收缩表,降低高水位线。


SQL> alter table stud shrink space cascade;

Table altered.

收缩表,降低高水位线,相关索引也收缩一下。


再收集一下表的统计信息。

SQL> exec dbms_stats.gather_table_stats(ownname=>'SHU',tabname=> 'STUD');

PL/SQL procedure successfully completed.


再看表的高水位线,已经降下来了。

SQL> select (b.blocks - a.empty_blocks - 1) hwm

from   user_tables   a,

       user_segments b

where  a.table_name = b.segment_name and

       a.table_name='STUD';

       HWM

----------

        46

select segment_name,blocks from user_segments where segment_name='STUD';


    整理索引

    索引碎片多了之后,也会发生性能问题,我们在AWR报告里看到db file sequential read等待事件,通常和效率不高的索引有关。如果我们的索引被删除的数据超过20%,或BLEVEL大于等于4,则我们的索引就需要整理了。补充一句,任何一种方法整理索引,都不应该在业务生产时间,都应该在停业时间,系统不繁忙的时间进行。也就是你要确认这个时间段此索引无人使用才可以整理。

查询数据库中blevel大于等于4的系引。

select owner||'.'||index_name as "owner.index_name",blevel    

from dba_indexes                                                   

where blevel>=4                                                    

order by blevel desc;


如果被删除的行del_lf_rows/lf_rows*100大于百分之20,则此索引建议整理。

col name for a20

select name,blocks,del_lf_rows/lf_rows*100,del_lf_rows/lf_rows*blocks from index_stats;


如果索引的状态为UNUSABLE,则需要整理索引。

select owner,index_name,status from dba_indexes where status='UNUSABLE';

在整理索引之前,我们需要看一下索引的owner是谁,只有和我们应用相关的才需要整理。




整理索引的方法有以下几种。

1、先准备好建立索引的脚本,然后将索引删除,重建索引。

select index_name,dbms_metadata.get_ddl('INDEX',INDEX_NAME,TABLE_OWNER) index_ddl

from user_indexes

where table_name ='STUD';


drop index shu.ind_stud_id;


create unique index shu.ind_stud_id on shu.stud ("STUD_ID");

这种方法速度快,好理解。影响关于此索引的dml。在实际生产中,可以使用。


2、rebuild,扫描现有索引块进行索引重建,需要两倍索引大小的空间,降低高水位线,执行速度快,会全程对表加锁,阻塞DML操作。是最常用的整理索引的方法。

alter index shu.ind_stud_id rebuild;


3、rebuild online对表进行全扫实现索引重建,会降低索引高水位线,一般执行速度慢,只在开始和结束时对表加锁,执行中间不阻塞DML操作。因为速度比较慢,中间过程又要维护DML的日志表,如果有DML操作,那么整理时间将大大拉长。所以谨慎使用。

alter index shu.ind_stud_id rebuild online;


4、coalesce接合索引,只对索引块做合并操作,不下降高水位线,可随时中断。全程不阻塞DML操作。因为会产生更多的redo日志。

alter index shu.ind_stud_id coalesce;


5、shrink索引,原理请参见shrink table。

alter index shu.ind_stud_id shrink space;

alter index shu.ind_stud_id shrink space compact;

alter index shu.ind_stud_id shrink space cascade;






7.4、性能优化的定义和范围

    本次性能优化的服务范围为樱澍保险的财险核心生产系统。

    将从应用层、数据库层、操作系统层到存储层对樱澍保险的核心生产系统进行全面的优化。

    本次数据库的优化可能涉及到对应用SQL进行调整,并针对应用中存在的待改进的问题提出解决建议。在优化过程中部分对应用的调整需要开发商的配合。

7.5、性能优化的目标:

    数据库的响应速度主要体现在数据库的等待时间和响应时间上。体现在如下几个方面:

    响应时间(Response time)

    CPU时间(Service Time)

    等待时间(wait time)

    查询量(User calls)

    事务量(transactions)

    Redo size/秒

    系统CPU(usr+sys%)

    系统IO等待(wio%)

    系统内存使用

    系统总体性能提升25%以上

    访问最少的块数

    将数据块保留在内存中

7.6、深入研究数据库系统的五大资源

     这五大资源和性能息息相关,需要一一排查是否存在性能瓶颈。

    1、内存

    2、程序(SQL)

    3、I/O

    4、CPU

    5、网络

七、数据库首次优化方案

         1、测量并记录当前性能。

         2、确定当前Oracle的性能瓶颈(等待什么)。

使用awrrpt,sqlrpt,addmrpt,sqltrace,ashrpt,tuning包等。

操作系统工具如top,sar,vmstat,iostat,osw等。

         3、确定当前的os是否有瓶颈,若有分析瓶颈的原因。

         4、操作系统核心参数的调整建议;包括信号量,内存分配限制。

         5、数据库内存配置的调整建议。

包括share pool, db_cache_size,keep池,recycle池,写进程数等。尽量使用手动管理内存大小,避免内存忽大忽小,减少抖动。

         6、I/O配置的调整。分散I/O,redo使用RAID10,热表cache到内存里,数据文件响应时间。

         7、清理不需要的历史数据,或把历史数据导入历史库。

         8、分析主要业务表, 为优化器的工作提供足够准确的统计分析数据,使CBO优化器能够生成优化的执行计划。关闭自动统计信息?

         9、使用keep池,将常用的表或其它对象keep到内存里来。

         10、使用rebuild online重建重点业务表索引。

         11、keep常用应用程序包。

         12、Keep常用小表。

         13、大表重组。

         14、关键索引重建。

         15、制定历史数据处理细则。

比如将一年前的数据导出生产库,导入历史库。

         16、将特大的生库表且又不能导入历史库的大表考虑进行分区。

比如按月分区,或按(半)年分区;按列表分区。

         17、确保代码可共享。

为了优化共享的SQL,使用绑定变量而不是文本值。

         18、尽可能避免或者减少排序操作。

尽可能确保排序在内存中执行,减少temp表空间使用量。

         19、减少分页和交换。

         20、应用分别分布于RAC两个或多个节点,避免交插访问。DRM的禁用?

         21、每一阶段调优完成,记录当前性能,和初期的(上一阶段的)性能做前后比较,量化调优收益。


八、风险防范措施

         1、确保数据库备份完整可用。

         2、所有操作和检查环节都使用事前完成并预演测试通过的脚本,避免临时修改脚本。

         3、每部分完成,通过检查确认无误,再进行其它部分,避免互相干扰。

         4、Oracle工程师和应用系统专家现场支持,及时处理突发问题。

九、数据库优化结果的保持

    在数据库系统没有大的变动的情况下,在服务期内,甚至更长的一段时间,通过定期的维护及相应的维护手段保证数据库优化后性能稳定。

    定期清理表中的垃圾数据或导入历史库,协助制定常用表的相关操作维护计划。

    优化表结构。

    减少操作语句间的相互影响(如锁表问题)。

    提高表操作语句的执行效率。

十、客户收益

         提高投资回报率

      合理、充分利用资源,延长系统使用寿命;

      优化运维成本,降低IT系统管理成本。

          提高系统稳定性

      在问题发生之前就发现并解决问题,因而可做到高枕无忧。

          提高运维水平

      系统优化的知识与经验能够得到传递,提高运维人员的能力。

          提高企业核心竞争力

      市场需求适应性增加,缩短新业务上线周期,提高IT系统的灵敏度,适应了飞速发展的业务需求。

      系统运行速度更快,可用性更高,客户满意度升高,企业竞争力提升。



图文推荐