BI系统运行一段时间后性能明显变慢了肿么办施系统慢数据库优化
【问题描述】
系统在运行了一段时间以后,在没有变更程序,且数据量没有大幅增加的时候,系统的执行效率明显变慢了肿么办?是求助研发人员,然后各种扯皮、谩骂乃至人生攻击?还是自已动手,丰衣足食?
【问题分析】
如果没有升级程序(为什么每次升级程序总是会让系统变得更糟而不是更好呢?这是一个值得研究的问题),数据量又没有大幅增加,系统硬件环境也没有变化,那么这个现象很可能是数据库本身的问题,引起数据库变慢的原因有很多,以下是几个比较可能的原因:
1、 数据库在进行了大量的删除、插入、更新后(ETL经常会干这个事情),由于数据库里不完全从物理上删除相应的数据,所以会导致表里占用了很多无用的物理块,表的索引中也会存在很多废弃的索引键,因此会导致访问表的时候额外读取了很多的数据块(block),包括表和索引,增加了IO的代价,因此效率降低,所以这就是为什么清表的时候一定要用truncate table而不要用delete from table方式的原因;
2、 Oracle是基于代价(cost)的优化模式,也就是oracle会根据数据库的统计信息(如表有多少条记录、有哪些索引、占用了多少数据块)对执行SQL各种可能的路径进行分析,从而在其中找到一个oracle认为最优的执行计划进行查询,但是在对数据进行了大量的删除、插入、更新后会导致数据库的统计信息越来越不准确,从而导致oracle误判,选择了一个较差的执行计划,引起执行效率降低;
3、 在对记录进行更新(update)的时候,由于记录都是一行一行紧密地存储在物理块(block)中的,因此当新update的记录比原来更长(占用的字节byte更多)的时候,在该记录原有的位置已经无法容纳该记录了,这时候oracle就会把记录迁移到另一个空闲的块中,并在原有的位置记录一个链接,指向新的块地址,这就叫行迁移,这样当数据被经常这样长期的蹂躏后,物理数据的存储就会变得非常乱,到处都是各种指针,导致数据库读取数据的效率变低;
4、 操作系统或者数据库都是按block(还记得安装oracle的时候可以改的block_size吗?)进行管理的,也就是oracle每次读数据的时候都会读block_size的整数倍。当某一条记录无法被完全放进一个block的时候,就会产生行链接,将一条记录的一部分存在block1里,另一部分存在block2里,并在block1里记录一个指向block2的指针,这样当数据被经常这样长期的蹂躏后,物理数据的存储就会变得非常乱,到处都是各种指针,导致数据库读取数据的效率变低。
【问题解决】
实施人员应该养成定期生成新的数据库统计信息的习惯,最简单的方法是重新生成所有表的统计信息,用“analyze table xxx compute statistics;”这个语法,注意对于大表来说这个语句的执行会较慢,因此应该在夜深人静的时候执行。
实施人员应该经常关注数据库的碎片情况(行链接和行迁移),以便及时优化数据库,检查碎片情况可以用下面的语句:analyze table xxx list chained rows into chained_rows。注意“chained_rows”是一张物理表,默认是不生成的,可以用这个脚本来生成:$ORACLE_HOME/rdbms/admin/utlchain.sql。
解决的方法如下:
1、 定期重新生成统计信息:
1) select ‘analyze table ‘||owner||’.’||table_name||’ validate structure ;’ from dba_tables where owner=’XXXX’ ;
2) select ‘analyze index ‘||owner||’.’||index_name||’ compute statistics;’ from dba_tables where owner=’XXXX’;
3) 将上述语句的查询结果放到sqlplus里执行一遍,当然最好的方式是用oracle的批命令来做,怎么用批命令自己上网搜去,下面提供一个例子:
分析所有表.txt
SET HEADING OFF
SET FEEDBACK OFF
select 'analyze table bi_fbk."'||table_name||'" delete statistics;' from dba_tables where owner='BI_fbk'
SPOOL C:\1.SQL
/
SPOOL OFF
SET FEEDBACK ON
start C:\1.SQL
SET HEADING ON
然后在sqlplus中调用上面的文本:“sql > @分析所有表.txt”
2、 清除行链接和行迁移,这有几种方法:
1) 用exp/imp的方式把表(可以单表操作,也可以全库操作)重新导一遍,则会重新生成新的数据存储;
2) 先将原表的数据移到备份表,再移回来即可:
1. create table 备份表 as select * from 原表;
2. truncate table 原表;
3. insert into 原表 select * from 备份表;
4. drop table 备份表。
3) 建一个备份表空间,将事实表从源表空间移到备份表空间,再从备份表空间移回原表空间,步骤如下:
1. Alter table xxx move tablespace 备份表空间;
2. Alter table xxx move tablespace 原表空间;
3. 重建该表的所有索引(否则表无法正常访问):
Alter index xxx rebuild;
系统运行一段时间后,提升其速度的方法总结
猜你喜欢
转载自yunqiang-zhang-hotmail-com.iteye.com/blog/1612540
今日推荐
周排行