对于一个7*24的在线生产系统来说,修改表定义(DDL)时一件非常痛苦的时,因为如果直接使用alter语句,将会在表上安放一个排他锁,也就是说在这期间所有的DML和select都无法操作,如果是一个大表,alter的时间将很长,在这期间应用会受到很大的影响。
幸好,从9i开始,Oracle提供了在线表重定义功能,在修改表定义的同时几乎不影响DML和select语句,因为排他锁只会在表上出现很短时间。但是在线表重定义需要额外的空间(大致等于原表空间大小)。
在线表重定义具有如下功能:
CREATE TABLE P95169.SHIFT_CASE ( SCID VARCHAR2(40) NOT NULL ENABLE, ESTID VARCHAR2(40), CLINICTYPEUUID VARCHAR2(40) NOT NULL ENABLE, EXPERTID VARCHAR2(40) NOT NULL ENABLE, CLINICADDRESS VARCHAR2(100), FEE NUMBER(10,0), UPDEPART VARCHAR2(50), GETTIME VARCHAR2(50), GETADDRESS VARCHAR2(100), ISOPEN NUMBER(1,0) NOT NULL ENABLE, SEXLIMIT NUMBER(1,0), AGETOPLIMIT NUMBER(3,0) DEFAULT 150, AGELOWERLIMIT NUMBER(3,0) DEFAULT 0, RCLIMIT NUMBER(8,0) NOT NULL ENABLE, SHIFTDATE CHAR(8) NOT NULL ENABLE, ISTIMEDIVISION NUMBER(1,0) NOT NULL ENABLE, ISSELECT NUMBER(1,0) NOT NULL ENABLE, WEEKDAY NUMBER(1,0) NOT NULL ENABLE, DAYSECTION NUMBER(1,0) NOT NULL ENABLE, ORDERINGCOUNT NUMBER(8,0) NOT NULL ENABLE, SHARERCCOUNT NUMBER(8,0) NOT NULL ENABLE, CREATETIME CHAR(14) NOT NULL ENABLE, STATE NUMBER(2,0) NOT NULL ENABLE, UPDATETIME DATE, CHANGEREASON VARCHAR2(1000), STATETIME CHAR(14) NOT NULL ENABLE, RELATEID VARCHAR2(40), HOSPDEPTUUID VARCHAR2(40) DEFAULT null NOT NULL ENABLE, TASKFLAG NUMBER(1,0), COL01 VARCHAR2(200), COL02 VARCHAR2(200), COL03 VARCHAR2(200), COL04 VARCHAR2(200), COL05 VARCHAR2(200), CASETYPE NUMBER(1,0) DEFAULT 0 NOT NULL ENABLE, HOSPRESOURCEID VARCHAR2(50), HOSPTIMESECTION VARCHAR2(50), HOSPTREATMENTTIME VARCHAR2(50), COMMENTS VARCHAR2(2000), HOSPITALUUID VARCHAR2(40), OPEN_TIME DATE, CONSTRAINT CK_SHIFTCASE_ORDERINGCOUNT CHECK (orderingcount>=0) ENABLE, CONSTRAINT CK_SHIFTCASE_SHARERCCOUNT CHECK (sharerccount>=0) ENABLE, CONSTRAINT PK_SHIFTCASE PRIMARY KEY (SCID) USING INDEX TABLESPACE DATA ENABLE ) TABLESPACE DATA;
SYS@TEST16>exec DBMS_REDEFINITION.CAN_REDEF_TABLE('p95169','shift_case',DBMS_REDEFINITION.CONS_USE_PK); PL/SQL procedure successfully completed.如果你采用by rowid,只要把上面的CONS_USE_PK替换成CONS_USE_ROWID即可。
CREATE TABLE P95169.SHIFT_CASE_INTERIM ( SCID VARCHAR2(40) NOT NULL ENABLE, ESTID VARCHAR2(40), CLINICTYPEUUID VARCHAR2(40) NOT NULL ENABLE, EXPERTID VARCHAR2(40) NOT NULL ENABLE, CLINICADDRESS VARCHAR2(100), FEE NUMBER(10,0), UPDEPART VARCHAR2(50), GETTIME VARCHAR2(50), GETADDRESS VARCHAR2(100), ISOPEN NUMBER(1,0) NOT NULL ENABLE, SEXLIMIT NUMBER(1,0), AGETOPLIMIT NUMBER(3,0) DEFAULT 150, AGELOWERLIMIT NUMBER(3,0) DEFAULT 0, RCLIMIT NUMBER(8,0) NOT NULL ENABLE, SHIFTDATE CHAR(8) NOT NULL ENABLE, ISTIMEDIVISION NUMBER(1,0) NOT NULL ENABLE, ISSELECT NUMBER(1,0) NOT NULL ENABLE, WEEKDAY NUMBER(1,0) NOT NULL ENABLE, DAYSECTION NUMBER(1,0) NOT NULL ENABLE, ORDERINGCOUNT NUMBER(8,0) NOT NULL ENABLE, SHARERCCOUNT NUMBER(8,0) NOT NULL ENABLE, CREATETIME CHAR(14) NOT NULL ENABLE, STATE NUMBER(2,0) NOT NULL ENABLE, UPDATETIME DATE, CHANGEREASON VARCHAR2(1000), STATETIME CHAR(14) NOT NULL ENABLE, RELATEID VARCHAR2(40), HOSPDEPTUUID VARCHAR2(40) NOT NULL ENABLE, TASKFLAG NUMBER(1,0), COL01 VARCHAR2(200), COL02 VARCHAR2(200), COL03 VARCHAR2(200), COL04 VARCHAR2(200), COL05 VARCHAR2(200), CASETYPE NUMBER(1,0) DEFAULT 0 NOT NULL ENABLE, HOSPRESOURCEID VARCHAR2(50), HOSPTIMESECTION VARCHAR2(50), HOSPTREATMENTTIME VARCHAR2(50), COMMENTS VARCHAR2(2000), OPERATIONDATE CHAR(8) DEFAULT to_char(SYSDATE,'yyyymmdd') ) PARTITION BY RANGE (OPERATIONDATE) ( PARTITION P2012 VALUES LESS THAN ('20130101'), PARTITION P201301 VALUES LESS THAN ('20130201'), PARTITION P201302 VALUES LESS THAN ('20130301'), PARTITION P201303 VALUES LESS THAN ('20130401'), PARTITION P201304 VALUES LESS THAN ('20130501'), PARTITION P201305 VALUES LESS THAN ('20130601'), PARTITION P201306 VALUES LESS THAN ('20130701'), PARTITION P201307 VALUES LESS THAN ('20130801'), PARTITION P201308 VALUES LESS THAN ('20130901'), PARTITION P201309 VALUES LESS THAN ('20131001'), PARTITION P201310 VALUES LESS THAN ('20131101'), PARTITION P201311 VALUES LESS THAN ('20131201'), PARTITION P201312 VALUES LESS THAN ('20140101'), PARTITION PMAX VALUES LESS THAN (MAXVALUE) ) TABLESPACE DATA;
alter session force parallel dml parallel 4; alter session force parallel query parallel 4;
BEGIN DBMS_REDEFINITION.START_REDEF_TABLE( uname => 'p95169', orig_table => 'shift_case', int_table => 'shift_case_interim', col_mapping => 'SCID SCID, ESTID ESTID, CLINICTYPEUUID CLINICTYPEUUID, EXPERTID EXPERTID, CLINICADDRESS CLINICADDRESS, FEE FEE, UPDEPART UPDEPART, GETTIME GETTIME, GETADDRESS GETADDRESS, ISOPEN ISOPEN, SEXLIMIT SEXLIMIT, AGETOPLIMIT AGETOPLIMIT, AGELOWERLIMIT AGELOWERLIMIT, RCLIMIT RCLIMIT, SHIFTDATE SHIFTDATE, ISTIMEDIVISION ISTIMEDIVISION, ISSELECT ISSELECT, WEEKDAY WEEKDAY, DAYSECTION DAYSECTION, ORDERINGCOUNT ORDERINGCOUNT, SHARERCCOUNT SHARERCCOUNT, CREATETIME CREATETIME, STATE STATE, UPDATETIME UPDATETIME, CHANGEREASON CHANGEREASON, STATETIME STATETIME, RELATEID RELATEID, HOSPDEPTUUID HOSPDEPTUUID, TASKFLAG TASKFLAG, COL01 COL01, COL02 COL02, COL03 COL03, COL04 COL04, COL05 COL05, NVL(CASETYPE,0) CASETYPE, HOSPRESOURCEID HOSPRESOURCEID, HOSPTIMESECTION HOSPTIMESECTION, HOSPTREATMENTTIME HOSPTREATMENTTIME, COMMENTS COMMENTS, SHIFTDATE OPERATIONDATE', options_flag => dbms_redefinition.cons_use_pk); END; /这里着重要讲一下col_mapping的设置:
[expression] column_name其中column_name是新表的列名,[experssions]表达式可以从原表的列、常量、操作符、函数调用等,比如上面的(NVL(CASETYPE,0) CASETYPE)就表示如果原表列CASETYPE为NULL,则新表的CASETYPE为0,否则就把原表该列的值赋予新表。
DECLARE num_errors PLS_INTEGER; BEGIN DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('p95169', 'shift_case','shift_case_interim', DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors); END; /注意:上面我们把
ignore_errors
设为true,表示即使中间有错误发生,存储过程不会退出,会一直运行直到结束,这时你一定要记得在下一步中查看是否有错误。
6. 从视图DBA_REDEFINITION_ERRORS查询上一步的错误信息:
SYS@TEST16>select object_name, base_table_name, ddl_txt from DBA_REDEFINITION_ERRORS; OBJECT_NAME BASE_TABLE_NAME DDL_TXT ------------------------------ ------------------------------ -------------------------------------------------------------------------------- PK_SHIFTCASE_2 SHIFT_CASE CREATE UNIQUE INDEX "P95169"."TMP$$_PK_SHIFTCASE_20" ON "P95169"."SHIFT_CASE_INT ERIM" ("SCID") PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 9437184 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FL ASH_CACHE DEFAULT) TABLESPACE "DATA" SYS_C009009 SHIFT_CASE ALTER TABLE "P95169"."SHIFT_CASE_INTERIM" MODIFY ("CASETYPE" CONSTRAINT "TMP$$_S YS_C0090090" NOT NULL ENABLE NOVALIDATE)类似以上的错误信息是因为中间表已经有主键和约束,所以导致失败,这些错误可以忽略。
BEGIN DBMS_REDEFINITION.SYNC_INTERIM_TABLE('p95169', 'shift_case','shift_case_interim'); END; /
BEGIN DBMS_REDEFINITION.FINISH_REDEF_TABLE('p95169', 'shift_case','shift_case_interim'); END; /只有在这个过程中,原表上有排他锁,但时间很短,对应用几乎没有影响,执行成功后,就用中间表替代原表。
注意:
注释(Comment)没有被复制到新表,记得重建Comment