当我终于有时间,有精力来总结分析那晚的经过时,事情已经过去了3天。
最大的教训是,在没有彻底弄清楚要执行的操作前,不要按回车键。
事情是这样的。
客户要删除指定时间以前的数据,有partition表, 有非partition表。对于partition表,客户要求用删除分区的方式,非pairtition表用delete命令。
ok,这个要求很好。
于是我准备sql
1)取出所有part表
select table_name, partitioning_type from user_part_tables;
2)取出所有part 索引
select index_name, partitioning_type,locality from user_part_indexes;
3)用dbms_metadata.get_ddl取出所有建表语句,取出partition 名,创建删除的语句。
set heading off
set echo off
set feedback off
set pages off
set long 90000
set linesize 300
spool all_part_new.sql
select dbms_metadata.get_ddl('TABLE','t1','user1') from dual;
select dbms_metadata.get_ddl('INDEX','IDX_1' ,'user1') from dual;
...
4)用ue查找PARTITION " ,把结果粘贴出来,修改成删除partition的sql。
alter table t1 drop partition "b1_P1";
...
5)执行sql
删除了几个表的分区,忽然客户反映应用异常,不能处理事务。
有索引不能访问,查看此索引,发现状态为INVALID.
alter index idx_a rebuild;
把所有invalid索引都重建,应用恢复正常。
为什么会出现索引invalid?
再查看9i文档
Managing Partitioned Tables and Indexes部分:
Leave the global indexes in place during the ALTER TABLE ... DROP PARTITION statement. Afterward, you must rebuild any global indexes (whether partitioned or not) because the index (or index partitions) will have been marked UNUSABLE
前面因为如果是local partition的索引,那么就直接删除了,没有关系,但是一些索引,比如主键,就变为invalid了。
最好的使用第三种方法:
Method 3:
Specify UPDATE GLOBAL INDEXES in the ALTER TABLE statement. This causes the global index to be updated at the time the partition is dropped.
ALTER TABLE sales DROP PARTITION dec98 UPDATE GLOBAL INDEXES;
alter table t1 drop partition "b1_P1" update global indexes;
6)遗憾的是,当时没有发现这个。
客户的客户,要求使用delete删除。
一级压一级。
于是使用删除命令。
因为有数据量较大的表(超过千万),所以想把比较大的表分阶段删除。
把前面取出的记录数保存到excel文件里面,安装大小排序,查找表,看其记录数,如果比较小就直接全部删除,
否则分阶段,三个月删除一次。
生成sql,执行。
7)执行时发现,一个千万级的表,没有分阶段删除。
(原因是查找表的时候,2个表的名字前面几个字符一样,结果看了表名更长的,
但是记录数为0的表,就没有加分段日期)。
担心执行时间很长,于是决定停止删除。
用top看占用cpu较多的oracle进程,通过
select sql_text from v$sqltext a,v$session b,v$process c where a.hash_value=b.sql_hash_value and b.paddr=c.addr and c.spid=&1 order by piece;
(spid输入oracle的unix进程号)确定是否是正在执行删除的sql.
然后alter system kill session 'sid,serial#';停止
停止时提示:已经被标识为删除,但是进程还在,查看oracle帮助,提示因为这个进程的
事务没有完成,所以没有马上停止。
这时候是在执行回滚。
在kill时,已经执行了30分钟左右。
等待回滚,大概1个小时。
7)回滚完成后,修改此sql,改为每3个月删除一次。
删除过程中,oracle crash。
查看alert文件,发现有不能扩展undo segment的提示,然后就是ora-600错误。
初步判断是undo segment不够引起的。
尝试启动instance,发现oracle的vg不可访问,发现vg已经处于deactive状态。
查看vg的一些命令,特别想直接vgchange -a -s vgdata,启动,而且客户也在催。
不过仔细想想,这个命令以前没有用过,是不是我理解的,如果不对,导致另外一个instance crash,
整个服务停止,那就麻烦更大了。
所以没有操作,要客户请求hp工程师支持。 此时是凌晨3点半左右。
等待...
到凌晨6点多,hp工程师到现场。
查看日志,了解情况,大概20分钟左右,因为关系重大,hp工程师也没有马上active vgdata,
在大概7点10分左右, 第二个instance crash。
现在已经没有更坏的情况了,hp工程师重启cluster,cluster自动启动oracle.
oracle启动正常,服务恢复正常。 (此时庆幸没有自己启动vgdata)
8)接下来要查第二个instance crash的原因
查看alert和相关文件,发现
*** 2006-10-13 07:06:55.757
*** SESSION ID:(10.1) 2006-10-13 07:06:55.709
TIMEOUT ON CONTROL FILE ENQUEUE
mode=X, type=0, wait=1, eqt=900
到此,应用正常,已经是上午12点,从9点到现场,到现在,已经是筋疲力尽。搭车回家。
后来查metalink ,
https://metalink.oracle.com/metalink/plsql/ml2_graphics.ShowProcessingMessage?p_ml2_text_code=PROGRESS_MSG&p_content_page=f?p=130:14:3374539482892071369::::p14_database_id,p14_docid,p14_show_header,p14_show_help,p14_black_frame,p14_font:NOT,153788.1,1,1,1,helveticaoracle建议:Check the alert log to see how often a logfile switch is taking place.Try and ensure that REDO log files are sized such that a log switchtakes place approximately every half hour during heavy load. This willreduce the number of times we need to obtain the control file enqueue.Tune your datafile layout to resolve I/O contention.Check with the Hardware vendor to ensure there are no hardware problemsand that you are on the latest OS patch level.
检查alert日志,归档只有一次,不是归档频繁引起 controlfile enqueue wait.
问hp工程师,也没有查出明显的cluster问题。
往下查,没有思路了。 只能提交oracle metalink。
非常郁闷的2天。