일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- CAS
- 가비지 컬렉터
- 동시성 문제
- 가비지 컬렉션
- 동시성
- Synchronized
- text
- MVCC
- Varchar
- Atomic Type
- Locking Read
- MySQL
- Di
- iterator
- 백엔드
- 자바
- reflection
- 스프링
- 데이터 타입
- db
- foreach
- Lock
- iterable
- jpa
- java
- gc
- Today
- Total
과정을 즐기자
무작정 데이터 타입을 VARCHAR(16683)로 하면 안되는 이유 본문
이번 글은 MySQL과 InnoDB 스토리지 엔진을 기준으로 작성하였습니다.
MySQL에는 여러 데이터 타입이 있습니다. 숫자형 데이터 타입, 문자열 데이터 타입, 날짜 시간 데이터 타입 등..
이 중에서 문자열 데이터 타입의 종류에는 CHAR, VARCHAR, TEXT 등이 있습니다.
CHAR는 고정 크기 문자열 방식이고 VARCHAR는 가변 크기 문자열 방식이고 TEXT는 긴 문자열을 저장할 때 사용합니다.
이때 한가지 의문이 듭니다.
VARCHAR가 가변 크기 문자열 방식이라면 TEXT를 사용하지 않고 그냥 최대 크기인 VARCHAR(16683)로 (65535 bytes)
선언하면 되지 않을까요? 어차피 10글자만 입력하면 실질적인 10글자인 40bytes를 저장하고 나머지 4byte는 길이정보로
사용하여 VARCHAR(16683)로 선언하더라도 44bytes만 사용하게 됩니다.
이렇게 아예 크게 선언한다고 저장 공간을 더 많이 사용하는 것도 아니고 나중에 더 큰 문자열을 받을 수도 있으니
유연한 설계가 아닐까요?
VARCHAR
여기서 한 가지 놓친 사실이 있는데 저장 공간을 많이 사용하지 않는다는 것에서 '저장 공간'은 SSD나 디스크를 말합니다.
즉, VARCHAR(16683)로 선언하든 VARCHAR(50)으로 선언하든 10글자만 입력하면 SSD나 디스크에 저장되는
데이터의 크기는 모두 같습니다.
하지만 메모리 버퍼에서의 저장은 달라집니다. MySQL과 InnoDB 스토리지 엔진은 메모리 포인터를 이용해서 레코드 데이터를
주고 받습니다. 메모리 버퍼에 실제 레코드의 크기에 상관없이 최대 크기로 할당합니다.
즉, VARCHAR(16683)로 선언하면 (16683 * 4 + 4) bytes의 공간을 메모리 버퍼에 미리 할당한다는 것입니다. (utf8mb4 기준)
그래서 가변 길이 방식이라고 무작정 VARCHAR(16683)로 선언하면 메모리 부족 문제가 발생할 수 있습니다.
그렇다면 메모리 버퍼에 미리 최대 크기로 할당해놓은 이유가 무엇일까요?
바로 여러 커넥션에서 공유해서 사용할 수 있도록 하기 위함입니다.
메모리 버퍼에 처음 할당을 해놓고 여러 커넥션이 재사용할 수 있게 했습니다.
따라서 가변 방식의 장점을 제대로 사용하기위해서는 무작정 VARCHAR(16683)로 선언해서는 안되는 것입니다.
TEXT
위에서 VARCHAR는 메모리 버퍼에 최대 레코드의 크기만큼 미리 할당한다고 하였습니다.
그렇다면 정말 긴 문자열을 저장해야 한다면 메모리에 미리 할당하는 것은 문제가 될 수 있습니다.
문자열 데이터 타입 TEXT는 메모리에 미리 할당을 하지 않고 매번 레코드를 읽고 쓸 때마다 필요한 만큼
메모리를 할당합니다.
만약에 100글자를 저장한다고 해도 메모리 버퍼 공간에는 TEXT 값을 위한 포인터 공간 8 bytes, 헤더 4bytes
총 12bytes만 저장하고 레코드를 읽고 쓸 때 필요한 만큼 메모리를 할당하게 됩니다.
정리
지금까지 살펴본 동작 방식으로 VARCHAR와 TEXT를 각각 언제 사용하면 될 지를 정리해보겠습니다.
VARCHAR는 메모리 버퍼에 미리 할당하기 때문에 우선 문자열의 길이가 너무 길면 안됩니다.
TEXT는 메모리 버퍼에 미리 할당하지 않고 레코드를 읽고 쓸 때 할당하므로 문자열의 길이가 긴 데이터를 저장할 때 적합합니다.
메모리 버퍼에 저장된 데이터는 여러 커넥션이 공유해서 사용할 수 있으므로 해당 컬럼이 자주 필요한 경우에 VARCHAR가
적합합니다.
참고한 자료
'Database' 카테고리의 다른 글
RDB는 정말 유연한 설계에 대응하는 것이 어려울까? (0) | 2024.03.24 |
---|---|
Lock을 이용한 트랜잭션 격리와 MVCC가 나온 이유 (0) | 2023.10.02 |
RDB에서 동시성 문제는 왜 발생하며 어떻게 해결해야 하나? (0) | 2023.09.30 |
InnoDB 스토리지 엔진 아키텍처 (0) | 2023.07.14 |
MySQL 엔진 아키텍처 (0) | 2023.07.11 |