CHAR vs VARCHAR
char와 varchar는 공통적으로 문자열을 저장할 때 사용하는 타입이다. 이때 최대 저장 가능 길이를 명시하는데, MySQL에서는 바이트 수를 의미하는 것이 아니라 문자의 최대 저장 갯수를 의미하는 것을 주의해야 한다.
다음으로 차이점을 살펴보면 char의 경우에는 고정된 길이의 문자열을 저장하는 반면 varchar는 가변 길이의 문자열을 저장한다. 예를 들어, char(10)와 varchar(10)이라고 했을 때 char의 경우에는 입력된 문자열 데이터 크기와 상관없이 나머지 공간이 공백 문자 데이터가 채워지면서 10 만큼의 공간을 고정으로 할당받고 varchar의 경우에는 입력된 문자열 데이터 크기에 맞춰 가변적으로 공간이 할당된다. 또한 최대 길이도 다르다. char의 경우 최대 char(255)까지 가능하고 varchar는 varchar(16383)까지 가능하다. 물론 바이트로는 varchar(65535)가 맞다.
Tip)
단, UTF8MB4와 같은 가변길이 문자셋을 사용하는 char 타입의 경우에는 varchar와 비슷하게 동작할 수 있다.
그리고 varchar의 경우 실제 길이를 사용하는 만큼 명시해야 메모리 효율성이 증가한다. 또 디스크 공간 효율 차이도 미미하게 있다. 즉 길이가 30 이하라면 varchar(255)보단 varchar(30)으로 사용하자.
인프런 Q&A - 참조 https://www.inflearn.com/questions/1290528)
Q. UTF8MB4 CHAR 경우 미리 할당된 데이터 보다 더 큰 데이터를 업데이트 하게 된다면 VARCHAR 처럼 처음 레코드가 저장되었던 공간은 delete marking후 새롭게 빈 공간에 레코드를 저장하게 되는걸까요? 예시 : CHAR(10)에 '한글'을 저장했다가, '한글 연습'을 업데이트 하는 경우 VARCHAR 처럼 동작하는지가 궁금합니다.
A. CHAR 타입의 길이가 얼마냐에 따라서 다릅니다. 동영상 강의 내용의 예제에서 언급했던 CHAR(10) 타입의 경우, "한글"을 저장하면 6바이트를 사용하고 4바이트는 비워두지만, "한글연습"으로 업데이트되면 12바이트가 필요해져서, 최종적으로는 다른 위치로 레코드가 옮겨지게 됩니다. 만약 "한글"에서 "한글날"로 업데이트되면 9바이트만 필요하기 때문에 위치가 옮겨지지 않고 그 자리에 그대로 업데이트될 수 있을 것으로 보여요.
위 사항을 읽고 나면 일반적으로 주민등록번호와 같이 고정된 길이의 데이터는 char가 적합하고 데이터 길이가 변동할 가능성이 있는 경우 varchar를 사용하면 좋을 것 같다는 생각이 든다. 물론 틀린 것은 아니지만, 크게 중요하지 않다. 즉 좋은 기준이 될 수는 없다. 예를 들어, 주민등록번호의 경우 char(13)을 사용할텐데, 사실 변경 가능성이 없기 때문에 varchar(13)을 써도 크게 차이가 나지 않는다. 그리고 고정된 길이의 데이터라도 저장되는 문자열의 최소 길이와 최대 길이의 차이가 클 경우 char 타입을 쓰면 낭비가 심할 것이다. 물론 최소 길이와 최대 길이 폭 차이가 심하지 않으면 낭비는 거의 없겠지만 변동이 거의 없다면 varchar를 쓰는게 더 좋다.
반대로, 값의 가변 길이 범위 폭이 좁고 자주 변경되는 경우라면 varchar보단 char가 좋다. 특히 인덱스된 컬럼의 경우에는 더 좋을 것이다. 예를 들어, 자주 변경되면서 UPDATE가 자주 일어나면 데이터 페이지 내부적으로 Fragmentation(조각화 현상)이 자주 일어나고 결국 공간을 미리 예약해두는 char보다 효율이 떨어지기 때문이다. 결론적으로 UPDATE가 일어날 때마다 레코드를 저장하는 공간을 확보하기 위해서 빈번한 Page Reorganize 작업이 필요할 것이다.
Tip)
Fragmentation은 DISK나 Memory 공간이 비효율적으로 사용되는 현상을 말하는데, MySQL같은 DB에선 데이터 삽입, 수정, 삭제 과정에서 데이터 페이지가 파편화되어 성능 저하가 발생할 수 있다. 이 Fragmentation은 대표적으로 Internal과 External Fragmenation이 있다. Internal은 고정된 블록(페이지)에 데이터를 저장할 때, 데이터 크기가 작아 남는 공간으로 인해 비효율적인 공간 사용이 일어나는 것을 말하고 External은 데이터 크기가 가변적일 때, 수정이나 삭제 후 남는 공간을 다른 데이터가 효율적으로 채우지 못하는 현상을 말한다. 즉 varchar는 데이터를 수정할 때, 길이가 늘어나거나 줄어드는 경우 페이지 안에서 데이터를 이동해야 하는 경우가 생기므로 External Fragmentaion이 빈번하게 발생할 수 있다. 데이터가 페이지 안에 남을 수 없게 되면 새로운 페이지로 이동하거나 데이터를 분산 저장하게 되어 성능 저하가 발생할 수 있다.
VARCHAR vs TEXT
varchar와 text 타입 모두 문자열을 저장한다. 이때 최대 65,535 바이트까지 저장이 가능하다. 단, varchar의 경우에는 테이블의 전체 row 크기에 영향을 받고 text의 경우엔 데이터를 실제 테이블의 메모리 페이지 밖에 별도로 저장하고 테이블에 포인터만 저장한다.
Tip)
TEXT 뿐만 아니라 TINYTEXT, MEDIUMTEXT, LONGTEXT 종류가 있다.
다음으로 차이점을 살펴보면 varchar의 경우 지정된 글자 수 만큼만 데이터가 저장이 가능하다. 하지만 text는 그렇지 않다. 그리고 주의할 점으로는 text의 경우에 인덱스를 생성하려면 인덱스 생성 시 반드시 Prefix 길이 지정이 필요하다. 물론 지정하더라도 인덱스로 지정할 수 있는 최대 길이를 넘어가면 인덱스 생성이 불가능하다. 이건 varchar도 동일하다. 또 text는 기본값을 설정하고 싶다면 표현식으로 지정해야 가능하다.
Tip)
text 인덱스 생성 예시: create index ix_text_column on table (text_column(100))
text 기본값 설정 예시: create table tbl (col text default ('abc'))
일반적으로 길이가 짧으면 varchar를 사용하고 길면 text를 사용한다. 하지만 이 기준은 애매하다. 예를 들어 varchar(5000)와 text 중 어떤 것을 사용하는 것이 좋을까? varchar 타입은 메모리 버퍼 공간을 미리 할당해두며 재활용이 가능하지만 text 타입은 필요할 때마다 할당하고 해제한다. 즉 컬럼 사용이 빈번하고 메모리 용량이 충분하다면 text보단 varchar를 쓰는게 더 효율적일 것이다. 단 varchar(5000)과 같이 길이가 긴 컬럼들을 자주 추가하면 Row 사이즈 제한(65,535 Byte)에 도달할 수 있으므로 적절하게 text 타입과 같이 사용하는 것을 권장한다.
varchar와 text의 경우에는 성능면에서 주의해야 하는 사항이 있다. 예를 들어 저장되는 사이즈가 크면 Off-Page 형태로 데이터가 저장될 수 있기 때문이다. 쿼리에서 Off-Page 컬럼의 참조 여부에 따라 쿼리 처리 성능이 크게 달라진다. 따라서 쿼리의 select 절에서는 가능하다면 필요한 컬럼들만 명시하는 것이 좋다. 뿐만 아니라 필요한 컬럼들만 명시하면 커버링 인덱스를 할 확률도 올라가기 때문에 항상 select 절에서는 필요한 컬럼만 명시하자.
Reference
Real MySQL - 이성욱님, 백은빈님
'Study > [무럭무럭 시즌 2] Real MySQL 8.0' 카테고리의 다른 글
무럭무럭 STUDY - 끄적끄적 (MySQL) (0) | 2024.09.28 |
---|---|
무럭무럭 STUDY - SELECT * 과 COUNT(*) 그리고 튜닝 (MySQL) (0) | 2024.09.21 |
무럭무럭 STUDY - InnoDB 스토리지 엔진 아키텍처 (0) | 2023.09.01 |
무럭무럭 STUDY - MySQl 엔진 아키텍처 (0) | 2023.08.19 |
무럭무럭 STUDY - 사용자 및 권한 (0) | 2023.08.16 |