📌 MSSQL 한 줄 INSERT할 때 실제 DB 용량은 얼마나 늘어날까?
개발하다 보면 한 줄씩 데이터가 쌓일 때 실제 DB 크기가 얼마나 증가하는지 궁금할 때가 있다.
저도 그런 상황이 생겨서 직접 확인해봤습니다.
우선 대략적인 증가 용량에 대한 공식부터 확인해보자.
📌 1. 증가 용량 추정 공식
고정 길이 데이터 + 가변 길이 데이터 + Row overhead
✅ 2. 계산 요소
항목 | 설명 |
고정 길이 데이터 | INT, DATETIME, MONEY, FLOAT, CHAR(n) 등 |
가변 길이 데이터 | VARCHAR(n), NVARCHAR(n), TEXT, XML 등 |
Row overhead | 보통 7~11바이트 정도의 관리용 메타데이터 공간 |
Page 구조 | 1 Page = 8KB, 1 Page에 여러 row가 들어감 |
할당 단위 | 실제 파일 크기는 Page 단위로 커짐 (8KB씩), 내부적으로는 64KB extent 단위로 증가 |
CREATE TABLE Test (
ID INT, -- 4 bytes
Name NVARCHAR(50), -- 최대 100 bytes (UTF-16)
Description NVARCHAR(1000), -- 최대 2000 bytes
RegDate DATETIME -- 8 bytes
)
- 고정길이: ID(4) + DATETIME(8) = 12 bytes
- 가변길이: NVARCHAR(50) + NVARCHAR(1000)
→ 입력값에 따라 다르지만, 최대치 기준 2100 bytes - Row overhead: 약 10 bytes
➤ 총 합: 약 12 + 2100 + 10 = 2122 bytes (대략 2.07KB)
※ 단, 실제로는 row 압축, page fragmentation, 기타 인덱스 등에 따라 달라짐
✅ 4. 실제 확인 방법 (테스트 후 측정)
-- 1. 현재 DB 사용량 확인
EXEC sp_spaceused 'Test'
-- 2. 10,000건 INSERT
INSERT INTO Test(ID, Name, Description, RegDate)
SELECT TOP (10000)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),
N'TestName',
N'TestDescription TestDescription TestDescription...',
GETDATE()
FROM master..spt_values a, master..spt_values b
-- 3. 다시 확인
EXEC sp_spaceused 'Test'
🔎 요약
상황예상 | 증가 용량 |
단순 테이블, 고정형 필드 | 약 50~100 bytes / row |
가변 문자열 포함 | 1~2KB / row |
대용량 텍스트, BLOB | 수 KB ~ 수 MB / row |
실제 DB 파일 증가 | 8KB Page 기준, 여유 공간 있으면 즉시 증가 안 할 수도 있음 |
✅ Insert 스크립트
DECLARE @i INT = 0;
WHILE @i < 100
BEGIN
INSERT INTO your_table_name (id, name, Description, RegDate)
VALUES (
@i,
'TestName',
'TestDescription TestDescription TestDescription...',
DATEADD(SECOND, @i, '2025-05-22T13:18:00')
);
SET @i += 1;
END;
그럼 이제 인덱스, page fragmentation 및 가변에 대해서도 추가적으로 확인해보자.
✅ page fragmentation, 기타 인덱스에 따른 내용
"한 줄(row)을 넣으면 DB 용량이 얼만큼 늘어날지 계산은 가능하지만,
실제로는 아래 같은 요소들이 있어서 정확히 딱 정해진 값으로 늘어나진 않다."
📦 왜 그런지? → 주요 원인
요소 | 설명 |
Row 압축 (Row Compression) | SQL Server가 저장 공간을 줄이려고 데이터를 압축해서 넣는 경우. 예: INT → 4바이트인데 1만 써도 1바이트만 쓸 수도 있음 |
Page Fragmentation (페이지 조각화) | 데이터가 SQL Server 내부에서는 8KB 단위(Page)로 저장됨. 비어 있는 페이지에 끼워 넣다 보면 공간 낭비가 생길 수 있음 |
인덱스 | 데이터를 빠르게 찾기 위한 구조인데, 인덱스도 공간을 차지함. 데이터를 넣으면 인덱스에도 같이 들어감 → 추가 공간 필요 |
✅ 1. Row 압축 (Row Compression)
🧠 설명:
SQL Server는 Row Compression 기능이 켜져 있으면, 실제 값이 작을 경우 데이터 타입보다 작은 크기로 저장한다.
📌 예시:
CREATE TABLE Test1 ( id INT, flag BIT );
- INT는 원래 4바이트지만, 값이 0~255 사이면 압축으로 1~2바이트만 사용 가능
- BIT는 1바이트 안에서 여러 값이 압축됨 (8개까지)
💡 결과:
예상 용량: 4 + 1 = 5바이트
압축 후: 1~3바이트로 줄어들 수 있음
✅ 2. Page Fragmentation (페이지 조각화)
🧠 설명:
SQL Server는 데이터를 8KB 페이지 단위로 저장하는데, 중간에 빈 공간이 생기면 데이터가 여러 페이지로 나뉘어서 저장될 수 있어다.
📌 예시:
- A, B, C 데이터를 순서대로 저장
- 나중에 A와 B 사이에 D를 넣으면 → 기존 공간이 꽉 차 있으면 새 페이지로 넘어가면서 공간 낭비
💡 결과:
- 한 줄당 1KB 데이터인데, 실제로는 8KB가 추가될 수 있음 (새 페이지 할당)
✅ 3. 인덱스(Index)
🧠 설명:
인덱스가 걸려 있으면 데이터를 INSERT할 때 인덱스도 함께 업데이트돼요. 이 과정에서 추가 공간이 소모됨.
📌 예시:
CREATE TABLE Test2 (
id INT PRIMARY KEY, -- 클러스터형 인덱스 생성됨
name VARCHAR(100)
);
INSERT INTO Test2 VALUES (1, 'Kim');
- 인덱스가 없으면: 1건만 저장
- 인덱스가 있으면: 데이터 + 인덱스 트리에도 반영 → 실제 공간 2배 이상 증가 가능
✅ 4. NULL / VARCHAR / NVARCHAR
🧠 설명:
가변 길이 문자형(VARCHAR, NVARCHAR)은 입력한 데이터 길이에 따라 실제 저장 공간이 다름.
NULL은 공간 거의 안 차지하고, 긴 문자열은 크게 차지함.
📌 예시:
CREATE TABLE Test3 ( content NVARCHAR(1000) );
- INSERT INTO Test3 VALUES (NULL); → 거의 공간 사용 안 함
- INSERT INTO Test3 VALUES (REPLICATE(N'A', 1000)); → 최대 2000바이트 사용
🔎 요약표:
요소 | INSERT 1건 예상 | 실제 증가 가능 공간 | 설명 |
Row 압축 | 5~10바이트 | 2~5바이트 | 값 작으면 압축 |
페이지 조각화 | 1KB | 최대 8KB | 새 페이지 할당 시 |
인덱스 | 100바이트 | 100~300바이트 | 인덱스 구조까지 반영 |
VARCHAR | 0~1000바이트 | 값 길이에 따라 다름 | 짧으면 공간 적게 차지 |
📌 정리
- 계산한 데이터 크기 ≠ 실제 증가한 DB 용량
- 내부적으로 SQL Server가 데이터를 압축하거나, 중간에 비효율적으로 넣거나, 인덱스를 자동 갱신하면서 예상보다 더 많이 또는 적게 용량이 늘어날 수 있다는 뜻이다.
그럼 이제 진짜 확인을 위해서 실제 샘플 테이블을 만들고 내용을 한번 확인해보자.
예시로 사용한 테이블은 CP_Table 라는 테이블.
✅ 테이블 구조
컬럼명 | 데이터 타입 | 비고 |
num | INT | PK, 자동 증가 |
note_num | INT | 노트 번호 |
user_num | INT | 사용자 번호 |
note_date | DATETIME | 노트 시간 |
h_type | NVARCHAR(15) | 노트 유형 (예: view, print 등) |
contents | NTEXT | 내용 (긴 텍스트 저장용) |
- num은 클러스터형 PK로 인덱스가 걸려 있고,
- h_type은 짧은 문자열,
- contents는 NTEXT라 별도 저장됩니다.
✅ MSSQL에서 한 줄 데이터가 차지하는 공간은?
예상하기 쉽게 각 컬럼이 차지하는 용량을 정리.
항목 | 용량 (대략) |
num, w_num, user_num | 4바이트씩 → 총 12바이트 |
w_date | 8바이트 |
h_type (NVARCHAR(15)) | 최대 32바이트 (2바이트 × 15 + 오버헤드) |
contents (NTEXT) | 본문에는 16바이트 포인터만 저장됨 |
Row 오버헤드 | 7~11 바이트 정도 |
📌 contents가 NULL이면 → 총 약 75~80바이트
📌 contents에 값이 있을 경우 → 내용 길이에 따라 추가로 증가
예시로 몇 개 비교하면:
contents 길이 | 실제 예상 용량 증가 |
NULL | 약 80바이트 |
1KB 텍스트 | 약 1.08KB |
10KB 텍스트 | 약 10.08KB |
100KB 텍스트 | 약 100.08KB |
📌 NTEXT는 별도 텍스트 페이지에 저장되기 때문에, row 자체는 항상 16바이트만 가지고 있음.
✅ 압축이나 기타 요소는?
위에서 생선한 테이블(CP_Table)은 현재 압축 기능이 없음(NONE) 상태이고,
추가 인덱스도 없이 PK 하나만 적용되어 있어서 예측하기 쉬운 구조.
하지만 실제 운영 환경에서는 다음 요소들도 공간에 영향을 줍니다:
- Row Compression: 숫자나 null이 많을 경우 압축되어 작게 저장
- Page Fragmentation: 중간에 빈 공간이 생기면 페이지 낭비 발생
- 인덱스: 인덱스 구조에 따라 INSERT 시 추가 공간 사용됨
- Page 단위 저장: 1건 저장했다고 바로 .mdf 용량이 증가하는 건 아님 (8KB 단위)
✅ 실제 위의 테이블에서 100건 / 1000건 데이터 넣었을 때의 용량 비교
- 기존 용량
- 100건 INSERT 후 용량
- 1000건 INSERT 후 용량
✅ 마무리
정리하면, 한 줄 INSERT한다고 바로 .mdf가 늘어나진 않지만,
Row 단위로 보면 평균 80바이트 + contents 길이만큼 추가라고 보면 된다.
운영 환경에서 용량 계산하거나, 테이블 사이즈 추정할 때 참고하면 좋을 것 같아서 정리해봤습니다.
저처럼 궁금하셨던 분들께 도움이 되길 🙌