문서유형ㅣ기술정보
분야ㅣ튜닝
적용제품버전ㅣTibero4 SP1 이상
문서번호ㅣTTUTI034
개요
데이터베이스 테이블의 컬럼 순서는 단순한 형식 문제가 아니라, 저장 효율과 성능에 직접적인 영향을 줍니다.
특히 컬럼 중 일부가 NULL 값을 허용(Nullable)하는 경우, 해당 컬럼의 위치는 테이블이 실제로 차지하는 저장 공간(Block 단위)에 영향을 줍니다.
본 분석은 NULL 컬럼이 테이블의 마지막에 위치할 때와 중간에 위치할 때의 물리적 저장 효율 차이를 실험적으로 검증하고, 이를 통해 테이블 설계 시 고려해야 할 컬럼 배치 원칙을 제시합니다.
이론적 배경
DBMS(Oracle, Tibero 등)는 한 행(Row)의 데이터를 컬럼 정의 순서대로 물리적으로 저장합니다.
각 컬럼은 실제 값이 존재하면 데이터를 저장하고, NULL인 경우에는 Null Indicator라는 내부 표시 정보만 저장합니다.
Null Indicator: 각 컬럼이 NULL임을 나타내는 내부 플래그(1바이트 이상)
핵심 차이점
NULL 컬럼이 중간에 위치할 경우
이후 컬럼들의 위치를 계산해야 하므로 각 NULL 컬럼마다 위치 정보가 필요합니다.NULL 컬럼이 마지막에 위치할 경우
이후 컬럼이 없으므로 해당 컬럼에 대한 정보 자체를 생략할 수 있습니다.
즉, NULL 컬럼이 뒤쪽에 위치할수록 저장 효율이 높아지며, 대규모 테이블에서는 이와 같은 미세한 차이가 전체 테이블 크기에 수십~수백 MB 단위의 차이를 만들 수 있습니다.
방법
두 개의 테이블을 생성하여 NULL 컬럼 위치만 다르게 정의하고, 동일한 데이터 양을 입력한 뒤 블록 사용량과 평균 행 길이(AVG_ROW_LEN) 를 비교했습니다.
1. 마지막 컬럼이 NULL인 테이블
CREATE TABLE T_END_NULL (
COL1 VARCHAR2(10) NOT NULL,
COL2 VARCHAR2(100) NOT NULL,
COL3 VARCHAR2(100) NULL,
COL4 VARCHAR2(100) NULL,
COL5 VARCHAR2(100) NULL
);
INSERT INTO T_END_NULL
SELECT TO_CHAR(LEVEL),
'A',
NULL, NULL, NULL
FROM DUAL
CONNECT BY LEVEL <= 100000;
COMMIT;2. 중간 컬럼이 NULL인 테이블
CREATE TABLE T_MID_NULL (
COL1 VARCHAR2(10) NOT NULL,
COL2 VARCHAR2(100) NULL,
COL3 VARCHAR2(100) NULL,
COL4 VARCHAR2(100) NULL,
COL5 VARCHAR2(100) NOT NULL
);
INSERT INTO T_MID_NULL
SELECT TO_CHAR(LEVEL),
NULL, NULL, NULL,
'A'
FROM DUAL
CONNECT BY LEVEL <= 100000;
COMMIT;3. 통계 수집 및 비교
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => USER, tabname => 'T_END_NULL');
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => USER, tabname => 'T_MID_NULL');
SELECT TABLE_NAME, NUM_ROWS, BLOCKS, AVG_ROW_LEN
FROM USER_TABLES
WHERE TABLE_NAME IN ('T_END_NULL','T_MID_NULL');
실험 결과
| 테이블명 | 행 수(NUM_ROWS) | 블록 수(BLOCKS) | 평균 행 길이(AVG_ROW_LEN) | 저장 효율 |
|---|---|---|---|---|
| T_END_NULL | 100136 | 256 | 5.8916393 | 효율적 |
| T_MID_NULL | 99105 | 320 | 5.88810261 | 비효율적 |
※ 실제 수치는 환경에 따라 달라질 수 있으나, 일반적으로 T_MID_NULL 쪽이 더 많은 블록을 사용합니다.
이 결과는 NULL 컬럼이 중간에 있을 경우 각 컬럼의 Null Indicator와 오프셋 정보가 추가로 저장되기 때문입니다.
내부 블록 구조 비교
마지막 컬럼이 NULL인 경우
블록 덤프 시 NULL 컬럼 데이터가 생략되어 표시되지 않습니다.
각 행에는 실제 데이터가 존재하는 컬럼만 저장됩니다.
결과적으로 한 블록에 더 많은 Row가 저장되어 블록 활용률이 높아집니다.
중간 컬럼이 NULL인 경우
블록 덤프 시 각 NULL 컬럼에 00 값(Null Indicator)이 명시적으로 존재합니다.
이후 컬럼의 오프셋을 계산하기 위해 위치 정보가 계속 유지됩니다.
불필요한 바이트가 누적되어 한 블록당 저장 가능한 Row 수가 줄어듭니다.
분석 요약
| 구분 | 마지막 컬럼이 NULL | 중간 컬럼이 NULL |
|---|---|---|
| NULL Indicator 저장 | 생략 가능 | 각 컬럼마다 존재 |
| Row당 저장 크기 | 작음 | 큼 |
| 한 블록당 저장 가능 Row 수 | 많음 | 적음 |
| 테이블 전체 크기 | 작음 | 큼 |
| 공간 효율 | 높음 | 낮음 |
결론
이 실험을 통해 NULL 컬럼의 위치가 테이블 저장 효율에 영향을 미친다는 사실을 확인할 수 있습니다.
NULL 컬럼이 중간에 위치하면
각 컬럼에 대한 Null Indicator와 위치 정보가 추가로 저장되어 공간 낭비가 발생합니다.NULL 컬럼이 마지막에 위치하면
불필요한 Null 표시 정보가 생략되어 테이블 크기가 줄어들고 블록 활용률이 높아집니다.
따라서 테이블 설계 시 다음과 같은 원칙을 적용하는 것이 바람직합니다.
설계 권장 원칙
- 가능한 한 NULL 컬럼은 테이블의 마지막에 배치합니다.
- 자주 조회되거나 인덱싱되는 NOT NULL 컬럼은 앞쪽에 배치합니다.