데이터베이스/0 + MySQL

[MySQL] CHAR vs VARCHAR

힘들면힘을내는쿼카 2024. 7. 6. 16:07
728x90
반응형

제가 개발을 하면서 DB에 가장 많이 사용하는 타입이 CHAR, VARCHAR 입니다.

그런데 CHAR와 VARCHAR의 공통점과 차이점에 대해서 정확하게 알지 못한 상태로

가변이면 VARCHAR, 고정이면 CHAR를 사용하면 된다! 정도로 이해하고 사용했습니다.

더 이상 이렇게 살면 안될거 같아 정리해야겠다는 마음이 들어서 포스팅을 작성하게 되었습니다.

 

CHAR의 VARCHAR 간단 소개

먼저 간단하게 공통점과 차이점에 대해서 정리해보겠습니다!

공통점

  • 문자열 저장용 컬럼
  • 최대 저장 가능 문자 길이 명시 가능! (byte 수가 아님!!)
    • CHAR(10), VARCHAR(10)은 모두 10글자 까지 저장 가능

차이점

  • CHAR는 값의 실제 크기에 관계없이 고정된 공간 할당
  • VARCHAR는 값의 실제 크기에 맞게 공간 할당
  • 최대 저장 길이
    • CHAR(255) vs VARCHAR(16383) → (65535 bytes)
  • VARCHAR저장된 값의 길이 관리하는 길이 저장 byte가 존재
  • CHAR 에서도 UTF-8mb4 와 같이 가변 길이 문자셋을 사용하는 경우에는 VARCHAR와 같이 길이 저장 byte가 존재!

 

 

공통점과 차이점을 알아 보았으니 실제로 어떻게 저장되는지 알아봅시다!

 

디스크에 CHAR, VARCHAR는 어떻게 저장될까?!

Latin1 character-set 을 사용하는 경우(고정길이 문자 셋)

first_name CHAR(10) 이라는 컬럼에 ABCD 를 저장하게 되면, 10 bytes의 공간을 할당한 상태에서 4 bytes에 ABCD가 저장되고 6 bytes는 비워두는 방식을 사용합니다.

 

first_name VARCHAR(10) 이라는 컬럼에 ABCD 를 저장하게 되면, 4 bytes에만 ABCD가 저장되고 길이 저장 byte에 1바이트가 할당 됩니다.

 

문자 셋에 관계없이, 꼭 필요한 만큼만 공간을 사용합니다.

  

UTF8mb4 character-set 을 사용하는 경우(가변길이 문자 셋)

UTF8mb4 문자셋을 사용하는 경우 1글자는 최대 4 bytes를 사용할 수 있습니다.

따라서 CHAR (10) 컬럼은 최대 40 bytes 까지 빈 공백으로 예약할 수 있는 것처럼 보입니다.!!

하지만, 실제 MySQL 서버는 빈 공백 공간을 예약할 때는 문자의 갯수보다는 byte 수로 빈 공백 공간을 예약하도록 동작합니다.

따라서 first_name CHAR(10)“한글” 이라는 2글자를 저장하면 한글 1글자는 3 bytes 씩 사용하기 때문에 총 6 bytes를 사용하게 됩니다.

그리고 byte 수 기준으로 공백 4개를 채우게 됩니다.

 

“한글연습” 이라는 4글자를 저장하면 12바이트를 사용하게 되고, 빈공간을 할당하지 않습니다.

어…? 왜 빈공간을 할당하지 않을까요?! 🤔

바로 CHAR(10) 컬럼 타입에 정의된 길이보다 더 큰 길이여서 추가로 빈 공간을 더 할당해 두지 않은 것 입니다!

 

first_name VARCHAR(10) 이라는 컬럼은 문자 셋에 관계없이, 꼭 필요한 만큼만 공간을 사용합니다.

  

저장되는 값의 길이 변동이 크지 않다면 CHAR 타입을 적용해보자!

일반적으로 고정된 길이의 값 저장은 CHAR 타입을 사용하고, 그외 경우에는 VARCHAR 타입을 사용해야한다?!

이 이야기는 틀린 말 입니다.!

 

VARCHAR를 사용하면 좋은 경우는 바로 CHAR 타입의 공간낭비가 심할 경우에 사용하면 좋습니다.

  • 문자열의 가변 폭이 큰 경우(1 ~ 100)

CHAR를 사용하면 좋은 경우는 바로 CHAR 타입의 공간낭비가 심하지 않는 경우에 사용하면 좋습니다.

  • 문자열의 가변 폭이 작은 경우(90 ~ 100)

 

저장되는 값의 길이 변동이 크지 않다면 CHAR 타입을 적용해보는 것이 좋습니다!

  

VARCHAR 컬럼 값의 길이 변경시 작동 방법

first_name VARCHAR(10) 컬럼에 ABCDABCDE로 UPDATE를 하게 된다면, MySQL 서버는 레코드의 길이가 ABCD 4글자에서 ABCDE 5글자로 변경되었기 때문에 기존에 레코드가 저장되어 있던 위치에 inplace 로 저장할 수 없다는 것을 알게 됩니다.

따라서 새롭게 빈 공간에 레코드를 저장하게 됩니다.

 

만약에 해당 레코드가 자주 변경되고, 삭제되는 작업이 반복 된다면 계속 새로운 빈공간을 찾는 일이 많아질 것입니다!!

VARCHAR 대신 CHAR를 사용한다면, 이러한 과정(새로운 빈공간을 찾는 작업)을 하지 않아도 됩니다!

따라서 문자열의 가변 길이 차이가 적고 자주 변경되는 컬럼인 경우에는 VARCHAR 대신에 CHAR를 사용하면 컬럼의 길이 변경시에 데이터 페이지 관리 작업을 최소화 할 수 있습니다!

 

결국, 레코드의 이동이 줄어들고 fragmentation이 줄어들면서 공간 절약 효과까지 얻을 수 있습니다!

 

정리

  • 데이터 페이지 내부의 조각화(fragmentation) 현상 발생
  • CHAR 타입 보다 공간 효율 떨어짐
  • 내부적으로 빈번한 Page Reorganize 작업 필요

 

  

정리

VARCHAR 보다 CHAR 선택하는 경우

  • 값의 가변길이 범위 폭이 좁다.
  • 값이 자주 변경된다.(특히 인덱스된 컬럼인 경우)

 

  

참고

 

Real MySQL 시즌 1 - Part 1 강의 | 이성욱 - 인프런

이성욱 | MySQL의 핵심적인 기능들을 살펴보고, 실무에 효과적으로 활용하는 방법을 배울 수 있습니다. 또한, 오랫동안 관성적으로 사용하며 무심코 지나쳤던 중요한 부분들을 새롭게 이해하고,

www.inflearn.com

 

 

 

 

728x90
반응형