최근 실시간 트랜잭션이 있는 테이블에 DDL을 중단없이 할 수 있을까?에 대한 질문을 받고 고민을 하게되었습니다.
단순 add면 상관없지만 default + not null이 있는 경우에는 작업 중에 트랜잭션은 대기해야 하는 상황이 발생하기 때문입니다.
단순 리오그 방법 중 하나로 정리를 했었는데, 사실 본래의 기능은 ONLINE으로 테이블의 구조를 변경할 수 있게 하는 기능이었습니다. 이것을 이용하여 가상의 시나리오를 진행해보도록 하겠습니다.
참고 : 이전의 제가작성한 redefinition 글
https://bae9086.tistory.com/81
TABLE_REDEFINITION
TTS 후 테이블이 이상이 있거나, 특이사항이 있을 때 새로 테이블을 생성하여(안의 데이터는 같음) 오브젝트 및 구성을 새로 만들어주는 편리한 프로시져입니다. 1. 작업 전 검증 exec dbms_redefinition
bae9086.tistory.com
https://bae9086.tistory.com/400
Online Redefinition시 Block 감소량 비교
Reorg 방법 중 하나인 Online Redefinition 을 수행했을 때 Block 감소량이 크지 않다는 이야기를 듣고 직접 테스트를 진행하여 확인해보았습니다. Reorg의 목적 중 하나인 HWM 을 낮추고 불필요하게 사용하
bae9086.tistory.com
Oracle Redefinition의 작동원리는 MVIEW를 활용하여 임시테이블을 만들고 그 임시테이블과 원본테이블의 변경사항을 실시간으로 적용시킬 수 있습니다. 그 중 MVIEW LOG를 이용하는데 이는 캡쳐형식으로 원본과 임시테이블의 데이터를 동기화 합니다.
아래는 MVIEW의 글입니다.
참고 : https://bae9086.tistory.com/525
Materialized View (MView)
Mview, (이전에는 snapshot으로 불린)는 로컬 또는 원격 테이블에 대해 쿼리를 기반으로 내용이 주기적으로 고쳐지는 테이블 세그먼트입니다. 쿼리형태로 저장된 뷰와는 달리 데이터가 직접 저장되
bae9086.tistory.com
시나리오.
-----------------------------------------------------------------
원본테이블 REF_ORIGINAL
임시테이블 REF_NEW
추가할 컬럼 E varchar2(30) default 'DEF' not null
------------------------------------------------------------------
1.세션1에서는 1초마다 데이터를 INSERT하는 자동 쉘 수행.
2.세션2에서는 Redefinition기능을 사용하여 임시테이블 생성하여 default와 not null을 추가
3.임시테이블과 원본테이블 sync
4. 전환
입니다.
1. 세션1에서는 1초마다 데이터를 INSERT하는 자동 쉘 수행
CREATE TABLE REF_ORIGINAL(A VARCHAR2(20) primary key, B NUMBER, C NUMBER,D VARCHAR2(30));
OS상에 쉘파일 생성
vi auto_ins.sh
sqlplus -s ysbae/oracle@PDB <<EOF
set timing on
insert into REF_ORIGINAL(A,B,C,D)
select dbms_random.string('x',10),
timestamp_to_scn(sysdate),
mod(timestamp_to_scn(sysdate),5),
'ABC'||dbms_random.string('x',10)
from dual;
commit;
exit
EOF
while true문을 사용하여 1초마다 수행하게 수행
$ while true;do sh auto_ins.sh sleep 1; done;
...
Elapsed: 00:00:00.01
1 row created.
Elapsed: 00:00:00.01
Commit complete.
...
2.세션2에서는 Redefinition기능을 사용하여 임시테이블 생성하여 default와 not null을 추가
임시테이블 생성
컬럼을 추가한 상태의 임시테이블을 생성합니다.
CREATE TABLE REF_NEW (A VARCHAR2(20) primary key, B NUMBER, C NUMBER,D VARCHAR2(30) , E VARCHAR2(30) DEFAULT 'DEF' NOT NULL);
redefinition 가능여부 체크
BEGIN
DBMS_REDEFINITION.CAN_REDEF_TABLE(
uname => 'YSBAE',
tname => 'REF_ORIGINAL',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID -- 실시간 DML 가능하게 함
);
END;
/
PL/SQL procedure successfully completed.
에러없이 수행되면 가능하다고 볼 수 있습니다.
PK가 없는 테이블일 시 아래에러가 발생할 수 있습니다.
ORA-12089: cannot online redefine table "YSBAE"."REF_ORIGINAL" with no primarykey
ORA-06512: at "SYS.DBMS_REDEFINITION", line 285
ORA-06512: at "SYS.DBMS_REDEFINITION", line 5943
ORA-06512: at line 1
테이블 건수 확인
SQL> select count(*) from REF_ORIGINAL
UNION ALL
select count(*) from REF_NEW; 2 3
COUNT(*)
----------
5604
0
redefinition 수행
col_mapping 부분이 중요한데 앞의 A는 원본테이블의 컬럼 뒤의 A는 임시테이블의 컬럼입니다. 저는 추가한 컬럼 이외의 컬럼은 이름과 구조가 같으므로 모두 동일한 이름으로 매핑해줍니다.
BEGIN
DBMS_REDEFINITION.START_REDEF_TABLE(
uname => 'YSBAE',
orig_table => 'REF_ORIGINAL',
int_table => 'REF_NEW',
col_mapping => 'A A, B B, C C, D D',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID
);
END;
/
건수확인시 비슷하게 건수가 들어왔습니다.
SQL> select count(*) from REF_ORIGINAL
UNION ALL
select count(*) from REF_NEW; 2 3
COUNT(*)
----------
6163
6121
임시테이블과 동일한 이름의 MVIEW가 생겼고, 원본테이블을 쿼리형식으로 데이터를 가지고있습니다.
I_SNAP$ 으로시작되는 인덱스도 자동으로 생성되는데 M_ROW$$컬럼인 인덱스가 생성되어 있습니다.
SELECT * FROM dba_mviews;
OWNER|MVIEW_NAME|CONTAINER_NAME|QUERY |QUERY_LEN|UPDATABLE|UPDATE_LOG|MASTER_ROLLBACK_SEG|MASTER_LINK|REWRITE_ENABLED|REWRITE_CAPABILITY|REFRESH_MODE|REFRESH_METHOD|BUILD_MODE|FAST_REFRESHABLE|LAST_REFRESH_TYPE|LAST_REFRESH_DATE|LAST_REFRESH_END_TIME|STALENESS|AFTER_FAST_REFRESH|UNKNOWN_PREBUILT|UNKNOWN_PLSQL_FUNC|UNKNOWN_EXTERNAL_TABLE|UNKNOWN_CONSIDER_FRESH|UNKNOWN_IMPORT|UNKNOWN_TRUSTED_FD|COMPILE_STATE|USE_NO_INDEX|STALE_SINCE|NUM_PCT_TABLES|NUM_FRESH_PCT_REGIONS|NUM_STALE_PCT_REGIONS|SEGMENT_CREATED|EVALUATION_EDITION|UNUSABLE_BEFORE|UNUSABLE_BEGINNING|DEFAULT_COLLATION|ON_QUERY_COMPUTATION|
-----+----------+--------------+----------------------------------------------------------------------+---------+---------+----------+-------------------+-----------+---------------+------------------+------------+--------------+----------+----------------+-----------------+-----------------+---------------------+---------+------------------+----------------+------------------+----------------------+----------------------+--------------+------------------+-------------+------------+-----------+--------------+---------------------+---------------------+---------------+------------------+---------------+------------------+-----------------+--------------------+
YSBAE|REF_NEW |REF_NEW |select A A, B B, C C, D D from "YSBAE"."REF_ORIGINAL" "REF_ORIGINAL"| 70|N | | | | | |DEMAND |FAST |PREBUILT |DIRLOAD_DML | | | |ERROR | | | | | | | |ERROR |N | | 0| | |YES | | | |USING_NLS_COMP |N |
SELECT * FROM dba_indexes WHERE table_name IN ('REF_ORIGINAL','REF_NEW');
OWNER|INDEX_NAME |INDEX_TYPE|TABLE_OWNER|TABLE_NAME |TABLE_TYPE|UNIQUENESS|COMPRESSION|PREFIX_LENGTH|TABLESPACE_NAME|INI_TRANS|MAX_TRANS|INITIAL_EXTENT|NEXT_EXTENT|MIN_EXTENTS|MAX_EXTENTS|PCT_INCREASE|PCT_THRESHOLD|INCLUDE_COLUMN|FREELISTS|FREELIST_GROUPS|PCT_FREE|LOGGING|BLEVEL|LEAF_BLOCKS|DISTINCT_KEYS|AVG_LEAF_BLOCKS_PER_KEY|AVG_DATA_BLOCKS_PER_KEY|CLUSTERING_FACTOR|STATUS|NUM_ROWS|SAMPLE_SIZE|LAST_ANALYZED |DEGREE |INSTANCES|PARTITIONED|TEMPORARY|GENERATED|SECONDARY|BUFFER_POOL|FLASH_CACHE|CELL_FLASH_CACHE|USER_STATS|DURATION|PCT_DIRECT_ACCESS|ITYP_OWNER|ITYP_NAME|PARAMETERS|GLOBAL_STATS|DOMIDX_STATUS|DOMIDX_OPSTATUS|FUNCIDX_STATUS|JOIN_INDEX|IOT_REDUNDANT_PKEY_ELIM|DROPPED|VISIBILITY|DOMIDX_MANAGEMENT|SEGMENT_CREATED|ORPHANED_ENTRIES|INDEXING|AUTO|CONSTRAINT_INDEX|
-----+---------------+----------+-----------+------------+----------+----------+-----------+-------------+---------------+---------+---------+--------------+-----------+-----------+-----------+------------+-------------+--------------+---------+---------------+--------+-------+------+-----------+-------------+-----------------------+-----------------------+-----------------+------+--------+-----------+-----------------------+-------+---------+-----------+---------+---------+---------+-----------+-----------+----------------+----------+--------+-----------------+----------+---------+----------+------------+-------------+---------------+--------------+----------+-----------------------+-------+----------+-----------------+---------------+----------------+--------+----+----------------+
YSBAE|SYS_C007610 |NORMAL |YSBAE |REF_NEW |TABLE |UNIQUE |DISABLED | |USERS | 2| 255| 65536| 1048576| 1| 2147483645| | | | | | 10|YES | 1| 24| 6121| 1| 1| 6030|VALID | 6121| 6121|2025-05-13 09:48:52.000|DEFAULT|DEFAULT |NO |N |Y |N |DEFAULT |DEFAULT |DEFAULT |NO | | | | | |YES | | | |NO |NO |NO |VISIBLE | |YES |NO |FULL |NO |YES |
YSBAE|I_SNAP$_REF_NEW|NORMAL |YSBAE |REF_NEW |TABLE |UNIQUE |DISABLED | |USERS | 2| 255| 65536| 1048576| 1| 2147483645| | | | | | 10|YES | 1| 25| 6121| 1| 1| 165|VALID | 6121| 6121|2025-05-13 09:48:50.000|1 |1 |NO |N |N |N |DEFAULT |DEFAULT |DEFAULT |NO | | | | | |YES | | | |NO |NO |NO |VISIBLE | |YES |NO |FULL |NO |NO |
YSBAE|SYS_C007608 |NORMAL |YSBAE |REF_ORIGINAL|TABLE |UNIQUE |DISABLED | |USERS | 2| 255| 65536| 1048576| 1| 2147483645| | | | | | 10|YES | | | | | | |VALID | | | |1 |1 |NO |N |Y |N |DEFAULT |DEFAULT |DEFAULT |NO | | | | | |NO | | | |NO |NO |NO |VISIBLE | |YES |NO |FULL |NO |YES |
SELECT * FROM dba_ind_columns WHERE index_name='I_SNAP$_REF_NEW';
INDEX_OWNER|INDEX_NAME |TABLE_OWNER|TABLE_NAME|COLUMN_NAME|COLUMN_POSITION|COLUMN_LENGTH|CHAR_LENGTH|DESCEND|COLLATED_COLUMN_ID|
-----------+---------------+-----------+----------+-----------+---------------+-------------+-----------+-------+------------------+
YSBAE |I_SNAP$_REF_NEW|YSBAE |REF_NEW |M_ROW$$ | 1| 255| 255|ASC | |
select * From dba_mview_logs;
LOG_OWNER|MASTER |LOG_TABLE |LOG_TRIGGER|ROWIDS|PRIMARY_KEY|OBJECT_ID|FILTER_COLUMNS|SEQUENCE|INCLUDE_NEW_VALUES|PURGE_ASYNCHRONOUS|PURGE_DEFERRED|PURGE_START|PURGE_INTERVAL|LAST_PURGE_DATE |LAST_PURGE_STATUS|NUM_ROWS_PURGED|COMMIT_SCN_BASED|STAGING_LOG|
---------+------------+------------------+-----------+------+-----------+---------+--------------+--------+------------------+------------------+--------------+-----------+--------------+-----------------------+-----------------+---------------+----------------+-----------+
YSBAE |REF_ORIGINAL|MLOG$_REF_ORIGINAL| |YES |NO |NO |NO |NO |NO |YES |NO | | |2025-05-14 15:08:10.000| 0| 0|YES |NO |
3.임시테이블과 원본테이블 sync
sync명령어는 언제든 계속 날릴 수 있습니다. 날리면 그때 시점으로 원본과 임시테이블을 동기화 해줍니다.
BEGIN
DBMS_REDEFINITION.SYNC_INTERIM_TABLE('YSBAE', 'REF_ORIGINAL', 'REF_NEW');
END;
/
SQL> select count(*) from REF_ORIGINAL
UNION ALL
select count(*) from REF_NEW; 2 3
COUNT(*)
----------
6636
6632
4. 전환(마무리)
REF_ORIGINAL이 E컬럼이 정상적으로 추가된것을 확인하였습니다.
다만 아무리 sync를 자주 날리고 근접하게 데이터를 동기화한다고 해도 실시간으로 들어오는 경우에는, 전환시에 데이터 유실이 조금 있을 수 밖에 없는거 같습니다. 그래도 중단없이 작업할 수 있는 강력한 방법임에는 확인을 하였습니다.
SQL> exec dbms_redefinition.finish_redef_table('YSBAE','REF_ORIGINAL','REF_NEW');
PL/SQL procedure successfully completed.
SELECT * FROM REF_ORIGINAL rn ;
A |B |C|D |E |
----------+-------+-+-------------+---+
8MFZN799CS|3895142|2|ABCR6QWHCW8X1|DEF|
J3RL3VHYCN|3895168|3|ABC7DTBLOQH3D|DEF|
QFDP93AYST|3895168|3|ABCT4TSHSFJT6|DEF|
...
SQL> select count(*) from REF_ORIGINAL
UNION ALL
select count(*) from REF_NEW;
COUNT(*)
----------
7475
7457
Online Redefinition은 "MVIEW 기반 CDC (Change Data Capture) 기술을 재정의용으로 활용한 것"이라고 볼 수 있습니다.
'Oracle > 운영' 카테고리의 다른 글
리스너(LISTENER)? (1) | 2025.05.08 |
---|---|
[PL/SQL] 동적 SQL과 정적 SQL로 각각 컬럼 명만 변경하여 수행되는 프로시저 작성 (2) | 2024.12.26 |
[SGA] library cache lock&pin 발생원인과 재현하기 (2) | 2024.12.13 |
Lob Partition 의 partition과 lob partition의 default attributes 설정 변경하여 자동으로 추가되는 파티션 압축되게 하기 (2) | 2024.11.22 |
[23ai] ai벡터검색 - ChatGPT를 이용하여 실시간 응답을 받기(RAG) (2) | 2024.11.15 |
댓글