Oracle数据库联机重定义讲解及错误处理
1.1. 关键字:联机重定义/SYNC_INTERIM_TABLE/GATHER_TABLE_STATS
1.2. 需求:数据表的清理机制需要优化
离线消息表采用delete的方式定期对过期的数据进行清理,在数据库检测日志中发现每次清理时间都特别长,且清理过程中数据库服务器IO和CPU使用率超高,希望对清理机制进行优化。
1.3. 分析:数据量大
1.涉及到的表有50张,从OFFMSG_0到OFFMSG_49,数据量比较大,最少的一张有一千多万数据,35G左右,最大的一张有几亿数据,超过300G
2.这些表使用比较频繁,超过8000万用户使用,在凌晨两三点也一直有数据进出,不能停机
3.现有的表清理机制是每天凌晨1点开始清理,delete掉日期在7天的数据
综合以上分析,可以将这些表进行分区,每天的数据写入到一个分区,清理时每天truncate掉对应的分区即可
4.实际测试,一张1700万数据的表(35G)进行联机重定义,需要20分钟
5.根据测试的结果估算,平均每张表需要执行超过30分钟,所有表执行完耗时超过25小时
6.运维可接受的一次执行脚本时间在4小时以内
7.要分区的表有正在执行的清理策略,当分区后,清理策略需要进行调整
综合以上情况分析,最终方案确定为:分成8个批次进行联机重定义,将每个联机重定义过的表应用新的清理策略,没有联机重定义的表还使用原有的清理策略
1.4. 操作
检查表空间
联机重定义过程中所需的表空间大小相当于当前已使用的表空间大小,也就是说要联机重定义的表所在的表空间至少要有一半的空余表空间、索引空间和undo空间。
这几个空间保证很关键,有几次我在执行的时候都是只关注了表空间,没有留意索引空间和undo空间,造成索引空间和undo空间被打爆了,联机重定义失败。
检查可否联机重定义
以DBA用户在数据库执行脚本
begin
DBMS_REDEFINITION.CAN_REDEF_TABLE('DBUSER',
'OFFLMG_0',
DBMS_REDEFINITION.CONS_USE_ROWID);
END;
/
出现’ PL/SQL procedure successfully completed.’,说明该表支持联机重定义。如果这个检查都没有通过的话,恭喜你,GG了。
在这里有一点要注意,我操作的这些表是没有主键的,所以使用了DBMS_REDEFINITION.CONS_USE_ROWID,当操作的表有主键时,应该使用DBMS_REDEFINITION.CONS_USE_PK。
Shell脚本
由于需要批量执行,我们将联机重定义脚本设计成shell脚本,在执行时通过参数指定要做哪些表。如下:
#!/bin/ksh
rm -f nohup.out
ORACLE_SID=DBSID;export ORACLE_SID
nohup sqlplus "/as sysdba" << EOF
set serveroutput on;
declare
V_SIGN NUMBER(10);
V_MAX_SIGN NUMBER(10);
V_CREATE_TABLE VARCHAR2(8000);
... ...
begin
V_SIGN := $1;
V_MAX_SIGN := $2;
WHILE V_SIGN <= V_MAX_SIGN LOOP
... ...
这样就可以通过./ShellName 5 8 这种方式指定每次要执行的表了。
创建中间表
在脚本中首先要创建中间表,如:
V_CREATE_TABLE :='CREATE TABLE OFFLMG_0_MY
( ID NUMBER(22,0) NOT NULL,
... ...
--STEP1:定义分区标示字段
PARTITIONFLAG NUMBER(8,0)
)
--STEP2:使用list分区方式
PARTITION BY LIST (PARTITIONFLAG)
(
--STEP3:定义第一个分区
PARTITION P_OFFLMG_0 VALUES (0) TABLESPACE IMLOG,
PARTITION P_OFFLMG_1 VALUES (1) TABLESPACE IMLOG,
... ...
--STEP4:定义默认分区
PARTITION P_OFFLMG_100 VALUES (default) TABLESPACE IMLOG
)
TABLESPACE IMLOG ';
EXECUTE IMMEDIATE V_CREATE_TABLE;
说明:
STEP1:中间表需要有一个分区标示字段,该字段的值作为分区的依据,该字段一般是NUMBER类型的
STEP3:将0值划分到分区P_OFFLMG_0分区,也可以用VALUES(0,1,2,3)的方式将若干个值划分到同一分区,也可以用VALUES LESS THAN(100)的方式将小于100的值划分到同一分区。
例:
PARTITION P_0 VALUES LESS THAN(100) ,
PARTITION P_1 VALUES LESS THAN(200) ,
这段脚本定义了P_0分区存放分区标示字段小于100的数据,P_1分区存放分区标示字段大于等于100小于200的数据。
STEP4:使用list分区时要注意,当你加上default分区后,以后需要添加分区时不能直接add,需要先drop掉default分区再add(会弄丢default分区的数据),或者从default分区split出新分区(不会弄丢default分区的数据,但是当default分区数据比较多时,split操作会特别慢)。
联机重定义
--STEP1:将中间表和要操作的表进行关联
DBMS_REDEFINITION.START_REDEF_TABLE('OFFLMG_0','OFFLMG_0_MY',
'ID ID,TO,......,PARTITIONFLAG PARTITIONFLAG',DBMS_REDEFINITION.CONS_USE_ROWID);
--STEP2:开始进行数据同步
DBMS_REDEFINITION.SYNC_INTERIM_TABLE('OFFLMG_0','OFFLMG_0_MY');
--STEP3:并行创建索引
V_CREATE_INDEX_A :='CREATE INDEX OFFLMG_0_MY_ID ON OFFLMG_0_MY (ID) LOCAL TABLESPACE IMIDX PARALLEL 16';
EXECUTE IMMEDIATE V_CREATE_INDEX_A;
--STEP4:将索引改为非并行的
V_ALTER_INDEX_A := 'ALTER INDEX OOFFLMG_0_MY_ID NOPARALLEL';
EXECUTE IMMEDIATE V_ALTER_INDEX_A;
--STEP5:进行数据整理、统计 DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>'DBUSER',TABNAME=>'OFFLMG_0_MY',ESTIMATE_PERCENT=> 0.1,DEGREE=>4,CASCADE=>TRUE);
--STEP6:联机重定义结束前再次同步数据
DBMS_REDEFINITION.SYNC_INTERIM_TABLE('OFFLMG_0','OFFLMG_0_MY');
--STEP7:联机重定义结束
DBMS_REDEFINITION.FINISH_REDEF_TABLE('OFFLMG_0','OFFLMG_0_MY');
DBMD_OUTPUT.PUT_LINE('Table OFFLMG_0 Redefined !!!');
说明:
STEP3:要操作的表比较大,创建索引时可以用并行创建的方式进行,大大减少索引创建时间,创建索引时要创建成本地索引。当索引创建完成后,要将索引改成非并行的。
STEP5:这个比较重要,新创建的表同步过来的数据没有生成统计信息,要手动整理一下,这样就可以正常使用了。
STEP6:联机重定义结束前一定要再次同步数据,因为整个操作是不停机执行的,在创建索引和整理数据的时候表中难免有新的数据进来,这个时候执行下同步就能保证新进来的数据也完整同步了。
错误处理
当表空间不足或其他原因造成联机重定义操作异常终止时,需要手动进行回退。脚本如下:
DBMS_REDEFINITION.ABORT_REDEF_TABLE ('OFFLMG_0','OFFLMG_0_MY');
说明:
这个时候只删除中间表是删除不掉的,因为联机重定义会创建实例化视图和实例化视图日志。需要先删除实例化视图日志,再删除实例化视图,最后才能删除中间表。
尾声
当联机重定义结束后, 需要确认数据完全一致,且数据表使用正常后才能删除掉中间表。
Oracle数据库联机重定义讲解及错误处理的更多相关文章
- Oracle数据库中字段定义为Char类型,Hibernate用该字段进行动态绑定参数查询,获取不到结果的问题
一.问题背景 产生环境:oracle数据库,hibernate操作 定义了一个表 create table STORE_INFORMATION ( id CHAR(32) not null, name ...
- Oracle数据库教程-数据定义语言(表操作)
创建表 建表语法: CREATE TABLE 表名 ( 列1 数据类型 [primary key], 列2 数据类型 default 默认值 [not null], …, constraint 约束名 ...
- Oracle数据库中序列用法讲解
序列(SEQUENCE)是序列号生成器,可以为表中的行自动生成序列号,产生一组等间隔的数值(类型为数字).其主要的用途是生成表的主键值,可以在插入语句中引用,也可以通过查询检查当前值,或使序列增至下一 ...
- Oracle数据库排序后分页查询数据错误问题解决
一.问题描述:根据更新时间倒序排序然后分页查询数据,但是点击分页操作的时候,会出现数据重复看似没有操作的情况 二.问题错误原因分析 分页查询的SQL语句: select * FROM (select ...
- 修改oracle数据库字段类型,处理ORA-01439错误
修改表PTLOG的列TYPE的char(1)为varchar(2)类型? 在PTLOG 表新增一列 TYPE_2:ALTER TABLE PTLOG ADD TYPE_2 VARCHAR2(2) de ...
- Oracle在线重定义(online redefinition)--将普通表改为分区表
使用Oracle的在线重定义技术,可以将Oracle的普通表改为分区表.操作如下: STEP1:测试表是否可以在线重定义,这里以unixdev数据库的LIJIAMAN.BSTEST为例 EXEC DB ...
- 基于 dbms_redefinition 在线重定义表
Oracle 支持在线重定义表,也就是说我们可以在修改表结构(DDL)的同时进行相关的DQL.DML操作,使得前端的DML根本感觉不到表结构实际上已经发生了变化,对于用户而言是完全透明的.当然在线重定 ...
- Oracle数据库备份、灾备的23个常见问题
为了最大限度保障数据的安全性,同时能在不可预计灾难的情况下保证数据的快速恢复,需要根据数据的类型和重要程度制定相应的备份和恢复方案.在这个过程中,DBA的职责就是要保证数据库(其它数据由其它岗位负责) ...
- oracle数据库常用SQL语句(11.29更新)
笔者日常工作中常用到的sql语句,现总结如下,留作日后查看. 1.按照两列中的最大值取 ,只取两列其中的一列 SELECT * FROM t_doc T ORDER BY GREATEST(T.Loa ...
随机推荐
- python 模块大全
logging time datetime sys os json random hashlib paramiko pymysql模块使用 subprocess pywi ...
- pandas apply 添加进度条
Way:from tqdm import tqdmimport pandas as pdtqdm.pandas(desc='pandas bar')df['title_content'] = df.p ...
- redis----------windows下安装redis以及PHP的redis扩展
1.redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(s ...
- 10 个非常实用的 SVG 动画操作JavaScript 库
SVG 通常可以用作跨分辨率视频.这意味着在一块高分屏幕上不会降低图片的锐度.此外,你甚至可以让SVG动起来,通过使用一些javascript类库.下面,我们分享一些javascript类库,这些 ...
- jQuery实现购物车物品数量的加减
基于jquery的一款代码,实现购物车数据的加减,在淘宝网.京东商城购物时时经常见到的一个功能,点击文本框两侧的“+”与“-”,就可以增加或减少文本框内的数字值,每次步长为1,当然这个是可以自己设置的 ...
- [转载]get、post异同
1. get是从服务器上获取数据,post是向服务器传送数据. 2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过 ...
- Android项目开发第二天,关于GitHub
一. 今天在网上学习了如何使用GitHub,了解了GitHub是干什么的. 作为开源代码库以及版本控制系统,Github拥有超过900万开发者用户.随着越来越多的应用程序转移到了云上,Github已经 ...
- CSS——对position定位和margin-top的理解
一.常见定位方式 1.positon:absolute (脱离文档流) 生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位 (这里的父元素是指定位方式为relative和abso ...
- jQuery创建、删除和修改html标签
1.在父标签内创建子标签,新创建的子标签放在父标签最下面 $(parent).append(son).$(son).appendTo(parent) <div class="d&quo ...
- JavaScript 字典
JavaScript 字典 字典以 key value 形式出现 使用: a = {'k1':'v1,''k2':'v2'} 获取值: a['k1'] 获取值:v1