본문 바로가기
데이터베이스

MySQL 성능 개선 3원칙: 데이터 타입 편

by 데이널 2024. 7. 3.

MySQL에서 어떻게 하면 성능을 좋게 할 수 있을까요? 아무래도 오라클 같은 상용 dbms보다 성능이 떨어진다는 점을 생각할 때 이 고민은 중요합니다. MySQL에서 데이터 타입의 선택은 Database 성능과 효율성에 중요한 역할을 합니다. 이번 글에서는 타입 결정을 내리는 데 도움이 되는 몇 가지 기본 원칙을 살펴보겠습니다.
 

사실 프로젝트에서 발생한 경험을 공유할까 합니다. Oracle의 테이블을 동일한 구조로 MySQL로 인터페이스를 해야 했는데요. 이럴 때는 대응되는 데이터 타입으로 변경이 필요합니다. 처음에 단순하게 아래와 같은 변환 방식을 생각했습니다.

Oracle 타입 MySQL 타입 비고
NUMBER DECIMAL 숫자 타입
VARCHAR, VARCHAR2   VARCHAR 문자 타입
CLOB LONGTEXT Large Object 타입
VARCHAR2(2000) 이상 TEXT 테이블 생성할 때 문자타입(varchar ) 길이 제한

그런데 생각할수록 너무 러프한 안이라는 생각이 들더군요. 그래서 과거에 경험했던 기억을 살려 정리해 보았습니다.



1원칙: 더 작은 크기 타입을 선택할 것

일반적으로 더 작은 공간을 차지하는 데이터 타입을 선택하는 것이 좋습니다. 더 적은 bytes를 차지한다는 말은 그만큼 블록 IO 적기 때문에 쿼리 성능을 향상됩니다. 정수 타입의 경우 값의 범위에 따라 TINYINT ~ BIGINT를 적합하게 선택해야 합니다. 예를 들어, TINYINT를 선택했다면 -128 ~ 127까지 숫자범위만 사용한다면 TINYINT를 사용하는 게 좋다는 말입니다.

 

MySQL 성능 개선 3원칙
MySQL 성능 개선 3원칙


그런데 128이 들어가면 어떻게 될까요? 그렇게 되면 범위를 넘어가기 때문에 에러가 납니다. 한번 데이터타입을 정하고 나면 바꾸는 게 쉽지 않기 때문에 처음에 잘 지정해야 합니다. 그래서 충분한 범위로 선택하되, 작은 크기일수록 좋습니다. UNSIGNED 속성을 사용하면 음수가 아닌 정수에 대한 저장 범위를 넓힐 수 있습니다.

 

MySQL 매뉴얼에도 가능하다면 더 작은 정수 유형을 사용하라고 가이드 하고 있습니다. INT보다 MEDIUMINT가 column이 25% 적은 공간을 사용하기 때문에 더 나은 선택이라고 말하고 있는데요. MySQL은 테이블의 사이즈가 임계점 이상 커지면 성능을 제대로 발휘하지 못하는데요. 그래서 컬럼 사이즈도 작게 잡는게 유리하다는 이야기입니다. 아래 링크 참고하시기 바랍니다. (출처: https://dev.mysql.com/doc/refman/8.4/en/data-size.html)

 

2원칙: 용도에 맞는 데이터 타입을 사용할 것

날짜, 시간, IP 주소와 같은 데이터를 문자열로 저장하지 마시기 바랍니다. MySQL은 날짜 및 시간 값에 대한 DATETIME,  IP 주소에 대한 정수와 같은 맞는 데이터 타입을 제공합니다. 데이터를 적절한 기본 형식으로 저장하면 효율적인 저장 및 검색이 보장됩니다.

1. BIGINT vs DECIMAL

그런데 헷갈리는 부분이 있습니다. BIGINT와 DECIMAL입니다. BIGINT의 경우 8byte를 차지합니다. DECIMAL의 경우 그때그때 다르죠. 저장 공간 차원에서는 DECIMAL이 압축을 하기 때문에 더 적은 공간일 수 있습니다. 그러면 BIGINT(10)의 경우 DECIMAL(10)으로 하는 게 더 낫지 않을까 생각하게 되죠. 하지만 DECIMAL은 정수 타입이 아닌, 소수점 타입 계산을 위한 유형입니다. 정수인 경우는 BIGINT가 속도가 빠릅니다.


만약 재무 데이터 또는 기타 정확한 소수점 값을 처리할 때는 DECIMAL 타입을 사용해야 합니다. 다른 숫자 유형(INT, BIGINT, FLOAT, DOUBLE 등)에 비해 저장 및 계산 비용이 증가하지만 반올림 오류 없이 십진수를 정확하게 저장할 수 있습니다.

 

2. TIMESTAMP vs DATETIME

날짜 및 시간 정보를 저장하는 데 TIMESTAMP 및 DATETIME을 사용할 수 있습니다. TIMESTAMP는 더 적은 저장 공간을 사용합니다. DATETIME의 경우 8bytes인데, TIMESTAMP는 4 bytes 잡히죠.

 

다만 범위가 더 작고(1970~2038) 시간대 설정에 민감합니다. 반면 DATETIME은 더 넓은 범위를 제공합니다. 하지만 Insert 또는 Update 시 타임스탬프를 자동으로 업데이트하지 않습니다.

 

3원칙: NULL 사용 최소화할 것

이 것은 MySQL 특성이기도 한데요. NULL이 성능에 미치는 영향입니다. NULL 값은 알 수 없거나 값이 누락될 경우 발생하는데요. 데이터베이스에서 인덱싱 및 비교를 복잡하게 만듭니다. 특히 칼럼을 인덱싱 하려는 경우 NULL 대신 0 또는 정해진 문자열로 채우는 것이 이득입니다. 오라클과 달리 MySQL에서는 기본값(default value)을 사용하는 것이 좋습니다.

 

그런데 왜 오라클과 달리 MySQL은 NULL에 대한 인식이 미흡할까요? 그 이유는 MySQL의 특성을 보면 알 수 있습니다.  MySQL은 오라클 대비 메모리 사용률이 상대적으로 낮습니다. 그래서 사양이 낮은 컴퓨터에서도 돌아가는 이점이 있죠. 1 mbytes 메모리 환경에서도 dbms을 운영할 수 있을 만큼 오버헤드가 작은데요. 이 부분을 좀 더 깊게 생각해 볼 필요가 있습니다. 


오라클이 메모리를 많이 사용하는 이유는 각종 통계정보를 통해 dbms를 더 효율적으로 활용하기 위해서 입니다. 어떻게 보면 MySQL은 어느 정도 그 부분은 타협을 했다고 할 수 있습니다. 그렇기 때문에 NULL에 대한 통계정보도 관리하지 않는다고 볼 수 있습니다. 


사용자 입장에서는 dbms가 해석하지 않는 명확한 방식으로 정의해야 혼돈이 없습니다. 이런 부분은 다음에 이야기할 MySQL 성능 개선 원칙: SQL 튜닝 편에서 다룰 이야기와도 맞닿아 있습니다. MySQL에서는 조인도 다양하게 제공하지 않다는 것을 알면 튜닝도 어떤 방향으로 진행해야 할지 답이 나옵니다. 

 

마치며

MySQL에서 데이터 타입 선택은 의외의 성능저하의 복병일 수 있습니다. 요구 사항에 맞는 데이터 타입을 엄격하게 적용하는 것을 추천합니다. 위에서 언급한 3원칙을 고려한다면 MySQL 데이터베이스에서도 원하는 성능을 유지할 수 있습니다.