메뉴 여닫기
개인 메뉴 토글
로그인하지 않음
만약 지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.

컬럼의 순서가 변경시 ROW의 물리적 구조변화

DB스터디
Dbstudy (토론 | 기여)님의 2025년 9월 26일 (금) 18:25 판 (→‎성능 모니터링)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

컬럼 순서 변경 시 기존 저장된 row의 물리적 구조 변화

  • Oracle 컬럼 순서 변경과 Row 구조 변화:

기본 원칙: 기존 Row는 변경되지 않음!

  • 테스트 데이터 생성 및 ROW 구조 확인
-- 초기 테이블 생성
CREATE TABLE column_order_test (
    id NUMBER,
    name VARCHAR2(20),
    status CHAR(1)
);

-- 초기 데이터 삽입
INSERT INTO column_order_test VALUES (1, 'John', 'A');
INSERT INTO column_order_test VALUES (2, 'Jane', 'B');
COMMIT;

-- 초기 row 구조 확인
SELECT DUMP(id) as id_dump, DUMP(name) as name_dump, DUMP(status) as status_dump
FROM column_order_test WHERE id = 1;
-- Row 구조: [Header][Length: id,name,status][Data: id,name,status]


컬럼 추가 시의 변화

새 컬럼 추가

-- 새 컬럼 추가 (항상 테이블 끝에 추가됨)
ALTER TABLE column_order_test ADD (new_col VARCHAR2(10));

-- 기존 데이터 조회
SELECT * FROM column_order_test;
-- 결과: id=1, name='John', status='A', new_col=NULL
--       id=2, name='Jane', status='B', new_col=NULL

기존 Row vs 새 Row 구조 비교

  • 기존 row 구조 (변경되지 않음!)
-- Row 1,2: [Header][Length: id,name,status][Data: id,name,status]
--          new_col은 NULL이므로 물리적으로 저장 안됨

-- 새 데이터 삽입
INSERT INTO column_order_test VALUES (3, 'Bob', 'C', 'NEW');
  • 새 row 구조
-- Row 3: [Header][Length: id,name,status,new_col][Data: id,name,status,new_col]
  • 물리적 구조 확인

SELECT 
    id,
    DUMP(id) as id_dump,
    DUMP(name) as name_dump, 
    DUMP(status) as status_dump,
    DUMP(new_col) as new_col_dump
FROM column_order_test;

실제 테스트로 구조 변화 확인

Row 크기 변화 측정

  • 테이블 통계 확인
ANALYZE TABLE column_order_test COMPUTE STATISTICS;

SELECT 
    table_name,
    num_rows,
    avg_row_len,
    blocks
FROM user_tables 
WHERE table_name = 'COLUMN_ORDER_TEST';

* Row별 실제 길이 확인 (VSIZE 함수 사용)
<source lang=sql>
SELECT 
    id,
    VSIZE(id) + VSIZE(name) + VSIZE(status) + NVL(VSIZE(new_col),0) + 8 as calc_row_size
FROM column_order_test;
-- +8은 row header + length array 추정치


Block Dump로 물리적 구조 확인

-- ROWID로 물리적 위치 확인
SELECT rowid, id, name, status, new_col FROM column_order_test;

-- 결과 예시:
-- ROWID                ID  NAME  STATUS NEW_COL
-- -------------------- --- ----- ------ -------
-- AAAEGkAABAAAQCYAAA    1  John   A     [NULL]   ← 기존 구조 유지
-- AAAEGkAABAAAQCYAAB    2  Jane   B     [NULL]   ← 기존 구조 유지  
-- AAAEGkAABAAAQCYAAC    3  Bob    C     NEW      ← 새 구조
```

컬럼 순서 변경의 실제 방법들

테이블 재생성 방법 (CTAS)


-- 1. 새 순서로 테이블 재생성
CREATE TABLE column_order_test_new AS
SELECT 
    id,           -- 1번째
    new_col,      -- 2번째 (순서 변경!)
    name,         -- 3번째  
    status        -- 4번째
FROM column_order_test;

-- 2. 기존 테이블 삭제하고 이름 변경
DROP TABLE column_order_test;
RENAME column_order_test_new TO column_order_test;

-- 3. 모든 row가 새 구조로 저장됨
-- 새 Row 구조: [Header][Length: id,new_col,name,status][Data: id,new_col,name,status]

DBMS_REDEFINITION 사용


-- Online 테이블 재정의 (운영 중에도 가능)
BEGIN
    -- 재정의 시작
    DBMS_REDEFINITION.START_REDEF_TABLE(
        uname => USER,
        orig_table => 'COLUMN_ORDER_TEST',
        int_table => 'COLUMN_ORDER_TEST_NEW'
    );
    
    -- 재정의 완료
    DBMS_REDEFINITION.FINISH_REDEF_TABLE(
        uname => USER,
        orig_table => 'COLUMN_ORDER_TEST', 
        int_table => 'COLUMN_ORDER_TEST_NEW'
    );
END;
/

Update 시 Row 구조 변화

기존 Row의 Update 동작


-- 기존 row에 새 컬럼 값 할당
UPDATE column_order_test SET new_col = 'UPDATED' WHERE id = 1;

-- Update 후 row 구조:
-- Before: [Header][Length: id,name,status][Data: id,name,status]
-- After:  [Header][Length: id,name,status,new_col][Data: id,name,status,new_col]

-- 주의: Row 크기 증가로 인한 Row Migration 가능성!


Row Migration 확인


-- Row migration 발생 확인
SELECT 
    table_name,
    num_rows,
    chain_cnt,
    (chain_cnt/num_rows)*100 as migration_pct
FROM user_tables 
WHERE table_name = 'COLUMN_ORDER_TEST';

-- Migration된 row 확인
ANALYZE TABLE column_order_test LIST CHAINED ROWS;


혼재된 Row 구조의 성능 영향

같은 테이블 내 다른 구조들


-- 혼재 상황 예시:
-- Row 1,2: [id][name][status] (old structure)
-- Row 3:   [id][name][status][new_col] (new structure) 
-- Row 1*:  [id][name][status][new_col] (updated old row)

-- 성능 측정
SET AUTOTRACE ON STATISTICS

-- 전체 스캔 시 다양한 row 구조 처리 비용
SELECT COUNT(*) FROM column_order_test WHERE new_col IS NOT NULL;
SELECT COUNT(*) FROM column_order_test WHERE name LIKE 'J%';


컬럼 접근 패턴 차이


-- 구조가 다른 row들의 컬럼 접근 비용
SELECT 
    id,
    CASE 
        WHEN new_col IS NULL THEN 'Old Structure'
        ELSE 'New Structure' 
    END as row_type,
    name,
    status,
    new_col
FROM column_order_test;

-- 실행계획에서 consistent gets 비교


실무 관점에서의 권장사항

컬럼 순서 변경 시나리오

  • 방법 1: 테이블 재생성 (완전한 구조 통일)

CREATE TABLE new_table AS 
SELECT col1, col3, col2, col4 FROM old_table;  -- 원하는 순서
  • 방법 2: 점진적 마이그레이션

-- 1단계: 새 컬럼 추가
-- 2단계: 데이터 이관  
-- 3단계: 기존 컬럼 삭제
-- 4단계: 컬럼 이름 변경
  • 방법 3: View로 논리적 순서 변경

CREATE VIEW logical_order_view AS
SELECT col1, col3, col2, col4 FROM physical_table;


성능 모니터링


-- 혼재된 구조의 성능 영향 확인
SELECT sql_id,
    executions,
    buffer_gets,
    disk_reads,
    elapsed_time/1000000 as elapsed_sec
FROM v$sql
WHERE sql_text LIKE '%COLUMN_ORDER_TEST%'
ORDER BY buffer_gets DESC;


  vpn_key 컬럼 순서가 변경 되면 row가 저장된 데이터 블럭 전체가 변경이 될까?

  playlist_add_check[요점정리]

1) 컬럼 순서 변경 시 Row 구조 변화
  1. 기존 Row: 물리적 구조 변경되지 않음(그대로 유지)
  2. 새 Row추가시 : 새로운 컬럼 순서로 저장**
  3. Updated Row: 새 구조로 재작성(Row Migration 가능)
  4. 혼재 상황**: 같은 테이블에 다른 구조의 row들이 공존
2) 성능 영향
  1. Full Table Scan: 다양한 구조 처리로 약간의 오버헤드
  2. Index Scan: 큰 영향 없음
  3. Update 연산: Row Migration 위험
  4. 메모리 사용: Row 구조 다양성으로 캐시 효율성 약간 저하
3) 실무 권장 사항 :
  1. 컬럼 순서 변경 시 테이블 재생성 고려
  2. 점진적 마이그레이션 계획 수립
  3. 성능 테스트 필수
  4. Row Migration 모니터링 지속
결론 : Oracle은 기존 데이터의 물리적 구조를 보존하면서도 새로운 구조를 수용하는 유연한 방식을 사용합니다!