记录一次spotlight(Oracle 监控工具)报警优化
报警信息:30.26% of rows fetches “continue” to another block (averaged over 30 seconds)
看到这个告警信息首先想到的是数据块可能发生了行链接或者行迁移。
下面是简单的叙述和优化方法
1) 什么是行链接和行迁移
1. 行链接
当一条记录太大,一个数据块无法将其存储时,Oracle就会将其存储在相链接的数据块中。如果一条记录中含有数据类型如:LONG、LONG RAW、LOB,行链接则无法避免。
2. 行迁移
当一个数据块已满,而一条记录在更新后长度增加了,或者表上新增加了字段,这时Oracle就会将整个记录迁移到一个新的数据块,原先的位置存放指向新位置的指针,这就是行迁移。记录的ROWID在行迁移之后保持不变。
2) 行迁移对数据库性能的影响
上述情况对数据库的性能是有一定影响的。系统在访问一条记录时,正常情况只需要访问1个数据块,但是当出现行链接/行迁移后,就需要访问至少2个数据块,增大了至少1倍的系统开销。
3)查询方法(可以通过性能报告获取有发生行迁移的表信息)
这里我是指定一些表做的优化,可以通全库全表一次分析并记录。
通过数据库工具脚本建立一个存放迁移行的表(oracle自带脚本)
SQL>@?/rdbms/admin/utlchain.sql
执行脚本后数据库会创建chained_rows数据表,分析行迁移的数据信息将记录在此表中。
–分析一下四个表
SQL>analyze table GLDW.BAS_EMPLOYEE_PHOTO list chained rows into chained_rows;
SQL>analyze table GLDW.DEPT_INFO list chained rows into chained_rows;
SQL>analyze table GLDW.EMPLOYEE_INFO list chained rows into chained_rows;
–查询表中的记录信息(count(*) 表示表中发生行迁移或行连接的总行数)
SQL>SELECT table_name, count(*) from sys.chained_rows GROUP BY table_name;
优化方法
一般有三种方法
1) exp/imp expdp/impdp(导入导出的方式)
方法简单(一般初级DBA都会),速度比较慢,并且可能会影响业务(不推荐)
2)通过重新插入的方式
步骤大概如下:
创建一个零时表
将发生行连接的行插入到临时表
删除行链接的行
从临时表中重新插入到表中
方法比较复杂,速度较快,较小程度影响业务(推荐)
3)move 的方式
方法简单,速度较快,占用空间大,基本不影响业务(推荐-本文以这种方式来讲解)
注意:这种方法索引一定会失效,所以操作后一定要重建索引(如果表上有索引)。
--EMPLOYEE_INFO
select tablespace_name,status from dba_tables where table_name = 'EMPLOYEE_INFO';
select table_name,index_name,status from dba_indexes where table_name = 'EMPLOYEE_INFO';
alter table GLDW.EMPLOYEE_INFO MOVE nologging parallel 2;
alter index GLDW.EMPLOYEE_INFO_IDX01 rebuild nologging parallel 2;
alter index GLDW.EMPLOYEE_INFO_IDX02 rebuild nologging parallel 2;
alter index GLDW.EMPLOYEE_INFO_IDX03 rebuild nologging parallel 2;
alter index GLDW.EMPLOYEE_INFO_IDX04 rebuild nologging parallel 2;
--BAS_EMPLOYEE_PHOTO
select tablespace_name,status from dba_tables where table_name = 'BAS_EMPLOYEE_PHOTO';
select table_name,index_name,status from dba_indexes where table_name = 'BAS_EMPLOYEE_PHOTO';
SELECT COUNT(*) FROM GLDW.BAS_EMPLOYEE_PHOTO
alter table GLDW.BAS_EMPLOYEE_PHOTO MOVE nologging parallel 2;
--DEPT_INFO
select tablespace_name,status from dba_tables where table_name = 'DEPT_INFO';
select table_name,index_name,status from dba_indexes where table_name = 'DEPT_INFO';
alter table GLDW.DEPT_INFO MOVE nologging parallel 2;
alter index GLDW.DEPT_INFO_ID1 rebuild nologging parallel 2;
alter index GLDW.DEPT_INFO_ID2 rebuild nologging parallel 2;
alter index GLDW.DEPT_INFO_IDX01 rebuild nologging parallel 2;
alter index GLDW.DEPT_INFO_IDX02 rebuild nologging parallel 2;
alter index GLDW.DEPT_INFO_IDX3 rebuild nologging parallel 2;
–move后删掉行迁移记录信息,重新分析行迁移数据数信息,重新查看是否move成功。
DELETE FROM chained_rows WHERE TABLE_NAME='BAS_EMPLOYEE_PHOTO ';
DELETE FROM chained_rows WHERE TABLE_NAME='DEPT_INFO';
DELETE FROM chained_rows WHERE TABLE_NAME='EMPLOYEE_INFO ';
–重新分析
SQL>analyze table GLDW.BAS_EMPLOYEE_PHOTO list chained rows into chained_rows;
SQL>analyze table GLDW.DEPT_INFO list chained rows into chained_rows;
SQL>analyze table GLDW.EMPLOYEE_INFO list chained rows into chained_rows;
–重新查看
SELECT table_name, count(*) from sys.chained_rows GROUP BY table_name;