주요 컨텐츠로 이동

SQL 데이터 타입: 참조 및 모범 사례

SQL 데이터 타입: 숫자, 문자, 날짜/시간 및 이진 타입. 스토리지 최적화, 쿼리 성능, 데이터 무결성 모범 사례 및 벤더 간 차이점을 마스터해 보세요.

작성자: Databricks 직원

  • SQL 데이터 타입은 삽입 시 값을 검증하여 데이터 무결성을 보장하며, 분석, BI 및 ML 워크로드 전반에서 데이터 손상을 방지합니다.
  • 적절한 크기의 데이터 타입을 선택하면 분산 시스템에서 CPU 캐시 활용도를 극대화하고 네트워크 전송 비용을 줄여 쿼리 성능을 향상시킵니다.
  • 데이터 타입 구현은 MySQL, PostgreSQL, SQL Server 및 Oracle에 따라 다르며, 스키마 이식성을 위해서는 정밀도 및 datetime 동작에 대한 벤더별 처리가 필수적입니다.

SQL 데이터 타입은 데이터베이스 테이블에서 열(column)이 어떤 값을 가질 수 있는지, 그리고 해당 값이 얼마나 많은 저장 공간을 차지하는지 정의하는 기본적인 사양입니다. SQL 데이터 타입을 이해하는 것은 데이터 파이프라인을 구축하거나, 쿼리를 작성하거나, 데이터베이스 스키마를 설계하는 모든 사람에게 필수적입니다. 이러한 타입이 데이터 무결성, 저장 효율성, 쿼리 성능을 직접 제어하기 때문입니다. 데이터베이스 테이블에서 열을 정의할 때 단순히 이름만 지정하는 것이 아닙니다. 해당 열에 어떤 종류의 정보가 저장되고 데이터베이스가 이를 어떻게 처리해야 하는지에 대한 일종의 계약을 수립하는 것입니다.

올바른 데이터 타입을 선택하는 것의 중요성은 아무리 강조해도 지나치지 않습니다. SQL 데이터 타입은 저장할 수 있는 값에 대한 논리적 규칙을 강제하여 처음부터 유효하지 않은 데이터가 입력되는 것을 방지합니다. 또한 쿼리가 얼마나 빨리 실행되는지, 테이블이 디스크 공간을 얼마나 차지하는지에도 극적인 영향을 미칩니다. 잘못 선택한 데이터 타입은 쿼리 속도를 늦추고, 저장 공간을 낭비하며, 데이터 파이프라인에 미세한 버그를 유발할 수 있습니다. 반대로 적절한 타입을 선택하면 장기적인 확장성을 개선하고 분석 워크로드, 실시간 애플리케이션, 머신러닝 피처 파이프라인 전반에서 데이터베이스 성능을 크게 향상시킬 수 있습니다.

SQL 데이터 타입은 크게 네 가지 그룹으로 분류됩니다. 수학적 계산을 위한 숫자형 데이터 타입, 텍스트를 위한 문자 및 문자열 데이터 타입, 이벤트 발생 시점을 기록하기 위한 날짜 및 시간 데이터 타입, 그리고 바이너리 데이터 및 기타 형식을 위한 특수 데이터 타입입니다. MySQL, PostgreSQL, SQL Server, Oracle 등 다양한 데이터베이스 시스템은 이름 지정, 정밀도, 저장 공간 요구 사항 등에서 약간의 차이를 두고 이러한 카테고리를 구현합니다. 이 가이드는 일반적인 데이터베이스 시스템 전반의 SQL 데이터 타입을 이해하기 위한 실용적인 참조 자료와 함께, 사용 사례에 맞는 올바른 타입을 선택하기 위한 모범 사례를 제공합니다.

데이터 타입이 강제하는 규칙 이해하기

데이터 타입은 단순한 레이블 그 이상입니다. 열의 타입을 INTEGER 또는 VARCHAR로 선언할 때, 데이터베이스 관리 시스템에 해당 열에 어떤 종류의 값이 속하고 쿼리 및 저장 중에 이를 어떻게 처리해야 하는지 정확히 알려주는 것입니다. 데이터베이스는 이 정보를 사용하여 데이터 삽입 시 데이터를 검증하고, 타입의 제약 조건을 위반하는 입력이 들어오는 것을 방지합니다. ACID 트랜잭션을 기반으로 하는 현대적인 데이터베이스 시스템은 동시 액세스 패턴 중에도 이러한 검증이 안정적으로 수행되도록 보장합니다.

간단한 예를 들어 보겠습니다. 열을 INTEGER로 정의하면 데이터베이스는 "hello"와 같은 텍스트나 3.14와 같은 정수가 아닌 값을 삽입하려는 모든 시도를 거부합니다. 이러한 검증은 자동으로 수행되며, 올바르지 않은 데이터 형식의 저장을 거부함으로써 데이터 무결성을 강제합니다. 이러한 강제 조치가 없다면 다운스트림 쿼리와 분석에서 손상되거나 일관되지 않은 데이터가 발생하여 잘못된 결과가 나오고 디버깅 시간이 낭비될 것입니다.

데이터 타입은 스키마를 사용하는 다른 개발자 및 데이터 엔지니어에게 의도를 전달하는 역할도 합니다. 어떤 열이 FLOAT 대신 DECIMAL로 정의된 것을 보면, 이 열이 반올림 오차를 허용하지 않는 정확한 통화 값을 저장한다는 것을 즉시 이해할 수 있습니다. 이러한 암묵적인 문서화는 오해를 줄이고 시간이 지나도 스키마를 더 쉽게 유지 관리할 수 있도록 해줍니다.

데이터 타입이 저장 공간 및 쿼리 성능에 미치는 영향

데이터 타입 선택은 테이블이 차지하는 디스크 공간과 쿼리 실행 속도에 직접적인 영향을 미칩니다. 저장 효율성은 클라우드 비용, 백업 시간, 처리를 위해 메모리에 로드할 수 있는 행 수에 영향을 미칩니다. 쿼리 성능은 부분적으로 데이터 타입 크기에 따라 달라집니다. 크기가 작은 타입일수록 CPU 캐시에 더 많은 행이 들어가고 저장소와 컴퓨팅 간에 전송해야 하는 데이터가 적어지므로 더 빠르게 처리할 수 있습니다. 매일 수백만 개의 행을 처리하는 ETL 파이프라인을 구축하는 팀의 경우, 이러한 최적화가 누적되어 측정 가능한 비용 절감 및 대기 시간 단축으로 이어집니다.

문자열 데이터 타입은 저장 공간 사용량에서 큰 차이를 보입니다. CHAR 열은 짧은 값을 저장하더라도 항상 선언된 전체 길이를 예약하고 빈 공간을 공백으로 채웁니다. 반면 VARCHAR 열은 실제 저장된 값에 필요한 만큼의 공간만 사용합니다. 대부분의 고객 이름이 30자 미만인 경우, 이를 VARCHAR(50)으로 저장하면 CHAR(50)에 비해 상당한 공간을 절약할 수 있습니다. 이러한 공간 절약은 수백만 행에 걸쳐 누적되며, 사용 가능한 메모리에 더 많은 데이터가 들어가므로 쿼리 대기 시간을 줄일 수 있습니다.

숫자형 타입 또한 성능에 영향을 미칩니다. INT로도 충분한데 BIGINT를 사용하면 저장 공간과 컴퓨팅 리소스가 낭비됩니다. 반대로 32,000을 초과하는 값을 저장해야 하는 열에 SMALLINT를 사용하면 오버플로 오류가 발생합니다. 데이터의 범위와 정밀도 요구 사항을 이해하면 값을 안전하게 저장할 수 있는 가장 작은 데이터 타입을 선택하여 데이터베이스를 빠르고 효율적으로 유지할 수 있습니다.

쿼리 성능을 크게 향상시키는 인덱스는 적절한 데이터 타입에 정의될 때 더 빠르게 작동합니다. TINYINT 열의 인덱스는 TEXT 열의 인덱스보다 더 효율적입니다. 적절한 크기의 숫자형 타입을 선택하고 매우 큰 텍스트 열에 대한 인덱스를 피함으로써, 전체 워크로드에서 인덱싱의 성능 이점을 배가시킬 수 있습니다. Apache Spark와 같은 분산 쿼리 엔진은 적절한 크기의 데이터 타입으로부터 특히 큰 이점을 얻습니다. 타입 크기가 작을수록 셔플 작업 중 네트워크 전송량이 줄어들기 때문입니다.

올바른 데이터 타입 선택하기

데이터 타입 선택의 황금률은 데이터를 안전하게 저장할 수 있는 가장 작은 타입을 사용하는 것입니다. 스키마 설계 시 이 원칙을 일관되게 적용하면 저장 효율성, 쿼리 속도, 시스템 확장성 측면에서 큰 이점을 얻을 수 있습니다. 타입을 선택하기 전에 스스로에게 질문해 보세요. 이 열에 포함될 수 있는 최대값은 얼마인가? 얼마나 많은 정밀도가 필요한가? 이 값이 NULL이 될 수 있는가?

숫자형 데이터의 경우 실제 데이터 분포를 살펴보세요. 열에 0에서 100 사이의 값이 포함된다면 TINYINT가 완벽합니다. 20억을 초과할 수 있는 고객 ID를 저장하는 경우 INT로 충분합니다. 실제로 20억을 초과하는 값을 저장해야 하는 경우에만 BIGINT를 사용하세요. 스키마의 수십 개 열에 걸쳐 이러한 구분을 적용하면 전체 테이블 크기를 20~30% 줄일 수 있어 쿼리 성능이 직접적으로 향상됩니다.

문자열을 다룰 때는 저장 공간과 유연성 사이의 절충안을 고려하세요. CHAR는 최대 길이를 강제로 선택하게 하며 항상 그 공간을 사용합니다. VARCHAR를 사용하면 가변 길이 데이터를 효율적으로 저장할 수 있지만, 데이터 잘림이 발생하지 않는 최대 길이를 선택해야 합니다. 이름에 VARCHAR(50)을 사용하는 것은 좋은 절충안입니다. 거의 모든 이름을 수용할 수 있을 만큼 충분히 크면서도, 데이터 품질 문제를 일으킬 수 있는 비정상적으로 긴 값이 실수로 저장되는 것을 방지합니다. 기사 본문이나 로그 메시지와 같이 매우 큰 텍스트 블록의 경우, 사전에 길이를 지정할 필요가 없는 TEXT 또는 CLOB 타입을 사용하세요.

프로덕션에 배포하기 전에 샘플 데이터로 선택한 사항을 검증하세요. 제안된 스키마가 적용된 테스트 테이블에 실제 데이터를 삽입하고 실제 저장 공간 사용량을 관찰해 보세요. 실행하려는 쿼리를 실행하고 성능을 측정해 보세요. 이러한 실증적인 접근 방식을 통해 선택한 데이터 타입이 실제로 실행 중인 워크로드를 잘 지원하는지 확인할 수 있습니다. 데이터베이스 플랫폼은 일반적으로 쿼리 실행 계획을 분석하고 최적화되지 않은 데이터 타입으로 인해 발생하는 느린 작업을 식별할 수 있는 도구를 제공합니다.

숫자형 데이터 타입

숫자형 데이터 타입은 숫자를 저장하며, 크게 두 가지 계열로 나뉩니다. 정수를 위한 정수형 타입과 소수점 이하 성분이 있는 숫자를 위한 데시멀(decimal) 또는 부동 소수점(floating-point) 타입입니다.

정수형 타입은 소수점이 없는 정수를 나타냅니다. INT라고도 불리는 INTEGER 데이터 타입은 정수 값에 가장 흔히 사용되는 선택지로, 약 -20억에서 +20억 사이의 값을 나타낼 수 있는 4바이트 숫자를 저장합니다. 더 작은 범위가 필요한 경우(예: 127을 초과하지 않는 나이 값을 저장할 때) TINYINT는 단 1바이트만 사용하므로 완벽한 선택입니다. SMALLINT는 2바이트를 차지하며 약 32,000까지의 값을 처리할 수 있어, 비교적 작게 유지되는 수량이나 카운트와 같은 열에 유용합니다. 8바이트 정수인 BIGINT는 천문학적인 숫자를 수용할 수 있으며, 분산 시스템에서 생성된 ID나 밀리초 단위로 측정된 타임스탬프를 저장할 때 필요합니다.

SQL 표준 문서에서 때때로 NUMERIC으로 불리는 DECIMAL 데이터 타입은 반올림 오차를 허용할 수 없는 금융 계산 및 기타 상황에 적합한 고정 소수점 숫자를 저장합니다. DECIMAL은 부동 소수점 연산에 내재된 근사치 없이 정확한 값을 저장합니다. DECIMAL(10,2)를 정의하는 것은 "총 자릿수가 최대 10개이고, 그 중 정확히 2자리가 소수점 오른쪽에 있는 숫자를 저장하겠다"는 의미입니다. 이러한 정밀도 덕분에 DECIMAL(10,2)는 99999999.99와 같은 값을 안전하게 저장하지만, 소수점 이하 자리가 두 개를 초과하는 값은 거부합니다. 은행과 회계 시스템은 금융 규정상 반올림 오차 없는 정확하고 감사 가능한 계산을 요구하기 때문에 DECIMAL에 의존합니다.

NUMERIC은 고정 소수점 데시멀 데이터의 SQL 표준 이름 역할을 하며, 대부분의 데이터베이스 시스템에서 DECIMAL과 동일하게 작동합니다. 일부 데이터베이스는 NUMERIC과 DECIMAL을 혼용하여 사용하는 반면, 다른 데이터베이스는 역사적인 이유로 이를 별도로 문서화합니다. 정확한 동작을 확인하려면 데이터베이스 문서를 확인하되, 실제로는 기능적으로 동일한 것으로 취급하면 됩니다.

숫자형 열이 있는 테이블을 생성해 보면 이러한 타입의 실제 적용 맥락을 잘 이해할 수 있습니다. 일반적인 판매 테이블은 다음과 같을 수 있습니다.

여기서 employee_id는 직원 ID가 보통 수백만 개에 달하기 때문에 INT를 사용합니다. age는 사람의 나이가 127세를 넘지 않으므로 TINYINT를 사용합니다. salary와 bonus_percentage는 급여 처리 과정에서 정확한 계산을 보장하기 위해 DECIMAL을 사용하는데, 급여 처리에서는 아주 작은 반올림 오류라도 조직 전체에 누적될 수 있기 때문입니다. Delta Lake와 같은 현대적인 데이터 플랫폼은 이러한 타입을 엄격하게 강제하여, 잘못된 타입의 데이터가 프로덕션 테이블에 삽입되지 않도록 보장합니다.

부동 소수점 수의 이해

부동 소수점 타입은 지정된 정밀도로 근사 수치 값을 저장합니다. FLOAT와 DOUBLE은 정확성 대신 속도와 범위를 선택한 IEEE 754 이진 표현을 사용합니다. FLOAT는 보통 4바이트를 차지하며 근사 값을 저장하고, DOUBLE은 8바이트를 차지하며 더 높은 정밀도를 제공합니다.

부동 소수점 표현은 많은 십진수 값을 이진수로 정확하게 표현할 수 없기 때문에 반올림 오차를 발생시킵니다. 예를 들어, 0.1은 이진 부동 소수점으로 정확히 표현할 수 없으므로 0.1이 포함된 모든 계산은 약간의 오차가 발생할 수 있습니다. 이러한 미세한 오류는 긴 계산 과정에서 누적되어 결국 눈에 보일 정도로 잘못된 결과를 초래합니다. 이러한 이유로 금전 데이터나 정확성이 중요한 다른 값에는 FLOAT나 DOUBLE을 절대 사용해서는 안 됩니다.

DECIMAL과 FLOAT 중 어떤 것을 선택할지는 사용 사례에 따라 다릅니다. 금융 데이터, 정밀한 과학적 측정 또는 정확성 검증이 필요한 계산에는 DECIMAL을 사용하세요. 근사값, 작은 오차가 허용되는 과학적 계산 또는 약간의 부정확함이 모델 품질에 영향을 미치지 않는 머신러닝 피처에는 FLOAT를 사용하세요. 적절한 크기의 데이터 타입을 사용하면 쿼리 성능이 향상되며, 모든 현대식 프로세서에서 부동 소수점 연산이 하드웨어적으로 가속화되기 때문에 FLOAT 연산이 DECIMAL 연산보다 빠릅니다.

제품 가격을 저장하는 두 가지 방법을 비교해 보세요.

두 번째 버전은 19.99와 같은 가격이 정확하게 저장되도록 보장하여 계산이나 표시 중에 반올림 오류가 전혀 발생하지 않습니다. 첫 번째 버전은 내부적으로 19.99를 19.989999...로 표현할 수 있어, 총액 계산 및 고객에게 표시되는 가격에서 미세한 불일치를 유발할 수 있습니다.

날짜 및 시간 데이터 타입

날짜 및 시간 타입은 이벤트가 발생한 순간이나 데이터가 유효한 것으로 간주되어야 하는 시점 등의 시간 정보를 저장합니다. 이러한 타입은 시계열 분석, 이벤트 로깅, 그리고 일이 발생한 시점을 추적하는 비즈니스 프로세스에 필수적입니다.

DATE 타입은 시간 구성 요소 없이 YYYY-MM-DD 형식으로 연, 월, 일의 날짜 부분만 저장합니다. 정확한 시나 분에 신경 쓰지 않고 고객의 생일이나 거래 날짜와 같이 어떤 일이 발생한 날만 기록해야 할 때 DATE를 사용하세요. DATE는 최소한의 저장 공간(보통 3바이트)을 차지하며 이벤트를 달력 일자별로 그룹화하는 쿼리를 단순화합니다.

TIME 타입은 날짜 없이 시, 분, 초의 시간 부분만 저장합니다. TIME은 DATE나 TIMESTAMP보다 덜 사용되지만, 영업시간이나 하루 중 예약 시간과 같이 반복되는 시간을 기록하는 스키마에 나타납니다.

TIMESTAMP 타입(MySQL 및 SQL Server와 같은 일부 시스템에서는 DATETIME이라고 함)은 YYYY-MM-DD HH:MM:SS 형식으로 날짜와 시간 정보를 모두 저장합니다. TIMESTAMP는 초 단위(또는 데이터베이스에 따라 더 미세한 단위)까지 정확하게 무언가가 발생한 완전한 순간을 캡처합니다. 대부분의 이벤트 기반 시스템은 TIMESTAMP를 사용하여 로그 항목이 생성된 시점, 주문이 접수된 시점 또는 센서 판독값이 도착한 시점을 정확하게 기록합니다. 스타 스키마 디자인으로 구축된 많은 분석 시스템은 효율적인 시간 분석 및 이력 팩트 추적을 위해 TIMESTAMP 키를 사용합니다.

쿼리 패턴에 따라 DATE와 TIMESTAMP 중 하나를 선택하세요. 비즈니스 로직이 이벤트를 달력 일자별로 그룹화하고 하루 중의 정밀한 시간이 필요하지 않다면 DATE가 더 깔끔하고 효율적입니다. 이벤트 간의 경과 시간을 계산하거나, 시간 내 트렌드를 감지하거나, 정확한 시간 순서를 유지해야 한다면 TIMESTAMP가 필요합니다.

날짜 및 시간 열 정의 예시:

여기서 birthdate는 태어난 시간이 아니라 그 사람의 생년월일만 중요하므로 DATE를 사용합니다. account_creation_date는 사기 패턴을 감지하거나 일 단위로 계정 연령을 계산하기 위해 계정이 생성된 정확한 시점을 알아야 하므로 TIMESTAMP를 사용합니다. preferred_contact_time은 특정 날짜 없이 "오후 2시에 전화해 주세요"와 같이 반복되는 시간을 저장하므로 TIME을 사용합니다.

날짜 및 시간 데이터의 시간대 고려 사항

시간 데이터에서 미묘하지만 중요한 문제는 시간대 처리입니다. 이벤트가 "2024-03-15 14:30:00"에 발생했다고 기록할 때, 이것이 뉴욕, 도쿄 또는 UTC 기준의 오후 2시 30분을 의미할까요? 동일한 시계 시간이 시간대마다 서로 다른 의미를 갖기 때문에 이 질문에 대한 답은 중요합니다.

가장 좋은 방법은 모든 타임스탬프를 시간대에 독립적인 시간 기준인 UTC(협정 세계시)로 저장하는 것입니다. 애플리케이션이 임의의 시간대에 있는 사용자로부터 이벤트를 수신하면 데이터베이스에 저장하기 전에 UTC로 변환하세요. 이 방식을 사용하면 모든 타임스탬프를 비교할 수 있으며, "어떤 이벤트가 먼저 발생했는가?" 또는 "이 이벤트들 사이에 시간이 얼마나 흘렀는가?"와 같은 질문에 명확하게 답할 수 있습니다.

PostgreSQL과 같은 일부 데이터베이스는 타임스탬프와 관련 시간대 정보를 모두 저장하는 TIMESTAMPTZ(시간대가 포함된 타임스탬프)를 지원합니다. 데이터를 검색할 때 데이터베이스는 필요한 경우 UTC 타임스탬프를 다시 원래 시간대로 변환합니다. 이 방식은 내부 일관성을 보장하면서 원래 시간대의 컨텍스트를 보존합니다.

SQL Server의 DATETIME 및 MySQL의 DATETIME은 시간대 정보를 포함하지 않으므로 저장하기 전에 시간을 UTC로 변환하고 사용자에게 표시할 때 다시 변환하세요. 일부 데이터베이스에서는 세션 설정이 타임스탬프 해석 방식에 영향을 미치므로 가정을 명확하게 문서화해 두세요.

보고서

멀티 에이전트 시스템, AI 활용 사례, 평가 등 주요 인사이트

문자 데이터 및 유니코드

문자 데이터 타입은 텍스트를 저장하며 고정 길이 및 가변 길이 변형이 있어 각각 다른 시나리오에 적합합니다.

CHAR는 고정 길이 문자열을 저장하며 항상 선언된 전체 길이를 사용하고, 실제 값이 더 짧으면 공백으로 채웁니다. CHAR(10)은 "hello"(5글자)를 삽입하더라도 행당 항상 정확히 10바이트를 차지합니다. CHAR는 미국의 우편번호(5자리)나 국가 코드(2글자)와 같이 거의 모든 값의 길이가 같을 때 유용합니다. 고정 길이 저장 방식은 인덱싱을 단순화하고 테이블 스캔 크기를 예측 가능하게 만듭니다.

VARCHAR는 가변 길이 문자열을 저장하며 실제 데이터에 필요한 만큼의 공간과 길이를 기록하기 위한 약간의 오버헤드만 사용합니다. "hello"를 저장하는 VARCHAR(100)은 약 7바이트("hello"에 5바이트, 길이 인코딩에 2바이트)를 차지하므로 동일한 값에 대해 CHAR(100)과 비교하여 93바이트를 절약할 수 있습니다. VARCHAR는 실제 데이터를 염두에 두고 크기를 지정해야 합니다. 이름이 50자를 초과하지 않을 것이라고 확신하는 경우에만 이름에 VARCHAR(50)을 선택하세요. 이름이 보통 30자이지만 가끔 50자에 도달할 수 있다면 VARCHAR(50)을 사용하는 것이 신중한 선택입니다.

TEXT는 선언된 최대 길이 없이 대량의 비정형 텍스트를 수용합니다. 크기가 매우 다양한 기사, 댓글 또는 문서에는 TEXT를 사용하세요. 일부 데이터베이스는 TEXT와 CLOB(Character Large Object)와 같은 더 전문화된 타입을 구분하지만, 대부분의 현대식 시스템은 내부 압축 및 스트리밍을 통해 TEXT를 효율적으로 처리합니다.

여러 언어의 문자가 포함된 다국어 텍스트의 경우 데이터베이스에 따라 유니코드를 지원하는 타입인 NVARCHAR 또는 UTF8 변형을 사용하세요. SQL Server의 NVARCHAR(national VARCHAR)는 모든 유니코드 문자를 지원하는 UTF-16 인코딩 텍스트를 저장합니다. PostgreSQL 및 MySQL은 적절한 데이터 정렬(collation) 설정을 통해 VARCHAR에서 UTF-8 문자 집합을 직접 지원합니다. 데이터베이스 기본값이 변경될 때 예기치 않은 동작이 발생하는 것을 방지하려면 테이블을 생성할 때 항상 문자 인코딩을 명시적으로 설정하세요.

문자열 열 정의 예시:

여기서 first_name과 last_name은 이름이 보통 짧지만 가변적이기 때문에 VARCHAR를 사용하여 CHAR에 비해 공간을 절약합니다. biography는 고객의 약력이 한 문장에서 전체 단락에 이르기까지 무엇이든 될 수 있으므로 TEXT를 사용합니다. country_code는 모든 국가 코드가 정확히 2글자이므로 고정 길이 저장 방식이 적합하여 CHAR(2)를 사용합니다.

이진 데이터 타입 및 이진 문자열

이진 데이터 타입은 텍스트가 아닌 원시 이진 데이터(바이트 시퀀스)를 저장합니다. 이러한 타입은 이미지, 파일, 암호화 해시 및 기타 텍스트가 아닌 콘텐츠를 저장하는 데 유용합니다.

BLOB(Binary Large Object)은 최대 크기 제한 없이 임의의 이진 데이터를 저장합니다. 이미지, PDF 문서, 비디오 또는 표준 타입에 맞지 않는 비정형 이진 콘텐츠에는 BLOB을 사용하세요. 데이터베이스에 파일을 저장해야 할 때 BLOB이 적합하지만, 많은 프로덕션 시스템은 대용량 파일을 Amazon S3와 같은 객체 스토리지 시스템에 저장하고 데이터베이스에는 파일 참조만 유지하는 것을 선호합니다.

VARBINARY는 명시적인 최대 크기를 가진 가변 길이 이진 데이터를 저장합니다. VARBINARY(256)은 최대 256바이트의 이진 데이터를 저장하며 실제 콘텐츠에 필요한 공간만 차지합니다. VARBINARY는 암호화 서명, 체크섬 또는 UUID와 같은 고정 크기 이진 데이터에 잘 작동합니다.

BINARY는 고정 길이 이진 데이터를 저장하며, 필요한 경우 null 바이트로 채웁니다. BINARY(16)은 항상 정확히 16바이트를 차지하므로 128비트 UUID와 같은 고정 크기 식별자를 저장하는 데 유용합니다. 너무 크게 선언하여 공간을 낭비하면 성능이 저하될 수 있으므로 BINARY 크기는 신중하게 지정해야 합니다.

실제로 대용량 파일은 데이터베이스 대신 오브젝트 스토리지에 저장하는 것이 보통 더 좋습니다. 오브젝트 스토리지는 데이터베이스 스토리지보다 저렴하고 대용량 파일 처리가 빠르며 확장도 더 쉽습니다. 파일 자체는 데이터베이스에 저장하지 말고, 파일 참조와 메타데이터만 데이터베이스에 보관하세요.

이진 열 정의 예시:

여기에서 content는 BLOB을 사용하여 실제 문서 데이터를 저장합니다. checksum은 VARBINARY를 사용하여 문서가 손상되지 않았는지 검증하는 SHA-256 해시(32바이트)를 저장합니다. uuid는 BINARY(16)을 사용하여 고정 크기 UUID 식별자를 저장합니다.

이진 데이터 사용 시 실질적인 고려 사항

전통적인 B-tree 인덱스는 값이 정렬 가능하고 비교 가능하다고 가정하므로 이진 열을 인덱싱하는 것은 까다롭습니다. BINARY 열은 정확히 일치하는 항목에 대해 인덱싱할 수 있지만 범위 쿼리에는 인덱싱할 수 없습니다. 데이터베이스에 이진 데이터용으로 설계된 특수 비트맵 또는 해시 인덱스가 없는 한 BLOB 열 인덱싱은 피하는 것이 좋습니다.

이진 콘텐츠의 데이터 무결성을 검사하려면 이진 데이터의 해시를 저장하는 별도의 checksum 열을 유지하세요. 손상이 의심되는 경우 해시를 다시 계산하여 저장된 값과 비교합니다. 이 방법은 전체 이진 콘텐츠를 다시 검사하는 것보다 훨씬 빠릅니다.

불리언(Boolean) 데이터 유형 및 불리언 데이터

불리언 데이터 유형은 참/거짓(true/false) 값을 저장하며 플래그, 상태 표시기, 예/아니요 결정에 필수적입니다. 참 및 거짓 값은 데이터 모델링을 간소화하고 NULL과 같은 잘못된 상태나 "yes" 또는 "1"과 같은 모호한 문자열을 방지합니다.

데이터베이스마다 불리언을 구현하는 방식이 다릅니다. PostgreSQL은 다양한 형식의 true/false, yes/no, on/off, 1/0을 허용하는 기본 BOOLEAN 유형을 제공합니다. MySQL은 BOOLEAN을 작은 정수로 취급하여 TINYINT(1)로 에일리어싱하며, 여기서 1은 참을, 0은 거짓을 나타냅니다. SQL Server는 불리언과 유사한 데이터에 BIT를 사용하여 값당 단일 비트를 사용해 참은 1, 거짓은 0으로 저장합니다(실제 스토리지는 다를 수 있음).

데이터베이스 간에 스키마를 마이그레이션할 때는 제공업체 간의 차이점을 이해하는 것이 중요합니다. PostgreSQL의 BOOLEAN은 SQL Server에 직접 대응하는 유형이 없으므로 대신 BIT를 사용해야 합니다. PostgreSQL의 유연한 참/거짓 입력("yes", "on", "1" 허용)을 가정하는 애플리케이션 코드는 SQL Server의 엄격한 0/1 요구사항에서 작동하지 않을 수 있습니다.

불리언 정의 예시:

세 가지 모두 참/거짓 값을 저장한다는 점에서 기능적으로는 동일하지만, 기본 유형 이름이 다르고 입력/출력 동작이 미세하게 다릅니다.

타입 캐스팅 및 변환

타입 캐스팅은 값을 한 데이터 유형에서 다른 데이터 유형으로 변환하는 것으로, 서로 다른 소스의 데이터를 결합해야 하거나 값의 해석 방식을 변경해야 할 때 필수적입니다.

암시적 변환은 데이터베이스가 작업을 가능하게 하기 위해 유형을 자동으로 변환할 때 발생합니다. INSERT INTO table_name (int_column) VALUES ('123')은 문자열 '123'을 정수 123으로 암시적으로 변환할 수 있습니다. 암시적 변환은 편리하지만 위험합니다. 의도하지 않은 변환이 수행되거나 변환이 경고 없이 실패하여 예기치 않은 결과가 발생할 수 있기 때문입니다.

CAST 또는 CONVERT를 사용한 명시적 변환은 정밀한 제어를 가능하게 하며 다른 개발자에게 의도를 명확하게 전달합니다. 명시적 캐스팅은 예기치 않은 오류를 방지하고 쿼리 성능을 더 예측 가능하게 만듭니다.

일반적인 변환에는 계산을 위해 문자열을 숫자로 캐스팅하거나, 연결을 위해 숫자를 문자열로 캐스팅하거나, 시간 범위로 필터링하기 위해 DATE 또는 TIMESTAMP로 캐스팅하는 작업 등이 있습니다.

CAST 사용 예시:

이러한 명시적 변환은 코드를 명확하게 만듭니다. 쿼리를 읽는 사람은 누구나 변환이 일어나고 있음을 즉시 이해하고 어떤 유형이 생성되는지 정확히 알 수 있습니다.

데이터베이스 벤더별 데이터 유형

SQL 데이터 유형은 MySQL, PostgreSQL, SQL Server, Oracle 간에 서로 다릅니다. 핵심 개념(숫자, 문자, 날짜/시간, 이진)은 보편적이지만 구체적인 유형 이름, 정밀도 및 스토리지 특성은 다릅니다.

MySQL은 불리언 값에 TINYINT를 사용하고(BOOLEAN을 TINYINT(1)로 에일리어싱), 가변 문자열에는 VARCHAR, 이진 데이터에는 BLOB을 사용합니다. PostgreSQL은 기본적으로 BOOLEAN을 지원하고, 크기 제한이 없는 대용량 텍스트에는 TEXT, 이진 데이터에는 BYTEA를 지원합니다. SQL Server는 대부분의 데이터베이스와 마찬가지로 INT 및 BIGINT를 사용하고, 문자열에는 VARCHAR, 대용량 이진 데이터에는 IMAGE를 사용합니다. Oracle은 숫자 값에 NUMBER, 문자열에는 VARCHAR가 아닌 VARCHAR2, 이진 데이터에는 BLOB을 사용합니다.

이러한 차이점은 스키마를 마이그레이션할 때 중요합니다. PostgreSQL의 TEXT 열은 제한 없이 데이터를 보관할 수 있지만, MySQL의 TEXT는 64KB 제한이 있어 더 큰 콘텐츠에는 LONGTEXT가 필요합니다. 아주 큰 텍스트의 경우 SQL Server에서는 VARCHAR(MAX)가 필요하지만, PostgreSQL의 TEXT는 이를 직접 처리합니다. Oracle의 NUMBER 유형은 대부분의 데이터베이스 숫자 유형보다 유연하여 정밀도와 스케일을 다르게 지정할 수 있습니다.

이식 가능한 스키마를 설계하기 전에 데이터베이스의 공식 문서를 참조하세요. 대상 데이터베이스 시스템에서 실제 데이터를 테스트하여 유형 동작에 대한 가정이 맞지 않는 예외적인 상황을 파악하세요.

데이터 유형 모범 사례

금융 데이터에는 DECIMAL과 같은 고정 정밀도 유형을 선호하고, 회계 또는 빌링 시스템에서는 부동 소수점 유형을 완전히 피하세요. 금융 데이터의 정확성은 타협할 수 없는 부분이며, DECIMAL의 정확성은 약간의 성능 비용을 감수할 가치가 있습니다. 현대적인데이터 웨어하우스 플랫폼에서 분석 시스템을 구축하는 조직은 거버넌스와 성능의 기반으로서 적절한 데이터 유형 선택을 점점 더 중요하게 생각하고 있습니다.

기술적으로는 가능하더라도 날짜나 불리언에 문자열을 사용하지 마세요. 날짜를 VARCHAR로 저장하면 날짜 연산이 어려워지고, 데이터베이스가 날짜 기반 쿼리를 최적화하지 못하며, 유효성 검사가 더 까다로워집니다. 불리언을 문자열로 저장하면 "false"가 "no"와 같은지 모호해지고 스토리지가 낭비됩니다. 이러한 값에 맞게 특별히 제작된 기본 DATE, TIMESTAMP, BOOLEAN 유형을 사용하세요.

특히 데이터베이스를 수년 동안 사용해 왔고 사용 패턴이 변경된 경우, 스키마 감사 중에 유형을 검토하고 최적화하세요. 더 이상 적용되지 않는 이유로 VARCHAR(1000)으로 정의된 열은 모든 행에서 공간을 낭비합니다. EXPLAIN PLAN 또는 데이터베이스의 쿼리 분석 도구를 사용하여 잘못된 유형 선택으로 인해 발생하는 느린 쿼리를 식별한 다음 리팩터링하세요.

유형 선택, 특히 예외적인 상황과 가정을 문서화하세요. 열이 INT 대신 TINYINT인 이유를 설명하는 주석을 달아두면 나중에 누군가 불완전한 이해를 바탕으로 이를 변경하는 것을 방지할 수 있습니다. 이러한 문서화는 범위가 중요한 숫자 유형에서 특히 중요합니다.

FAQ

CHAR와 VARCHAR의 차이점은 무엇인가요?

CHAR는 고정 길이 문자열을 저장하며 항상 선언된 전체 크기를 사용하고 공백으로 채웁니다. VARCHAR는 가변 길이 문자열을 저장하며 실제 데이터에 필요한 만큼의 공간만 사용합니다. 국가 코드(항상 2글자)와 같이 고정된 크기의 데이터에는 CHAR가 더 효율적이고, 이름과 같이 가변 길이 데이터에는 VARCHAR가 더 효율적입니다. 문자열 데이터 유형은 SQL 열의 데이터 입력 규칙을 적용하며, CHAR와 VARCHAR 중 무엇을 선택하느냐는 데이터베이스 시스템의 스토리지와 성능 모두에 영향을 미칩니다.

FLOAT 대신 DECIMAL은 언제 사용해야 하나요?

DECIMAL은 정확한 값을 저장하고 반올림 오류를 방지하므로 정밀도가 중요한 금융 데이터에 필수적입니다. FLOAT는 근사값을 더 빠르게 저장하지만 반올림 오차가 발생합니다. 금전적 금액, 정밀한 과학적 측정, 정확성 검증이 필요한 계산에는 DECIMAL을 사용하세요. 작은 오차가 허용되는 근사값, 머신러닝 피처, 과학적 컴퓨팅에는 FLOAT를 사용하세요. 올바른 데이터 유형을 선택하는 것은 금융 시스템의 데이터 무결성에 매우 중요합니다.

DATE와 TIMESTAMP 중 어떻게 선택해야 하나요?

고객의 생년월일이나 거래 날짜와 같이 시간 정보 없이 달력 날짜만 기록하면 되는 경우에는 DATE를 사용하세요. 이벤트 타임스탬프나 거래 완료 시간과 같이 시, 분, 초를 포함한 정확한 시간 정보가 필요한 경우에는 TIMESTAMP를 사용하세요. 날짜 및 시간 유형은 이벤트가 발생한 시점을 기록하는 데 사용되며, 올바른 유형을 선택하면 쿼리가 간소화되고 스토리지 낭비를 방지할 수 있습니다.

문자 데이터 유형의 최대 길이는 얼마인가요?

최대 길이는 데이터베이스마다 다릅니다. VARCHAR는 일반적으로 MySQL에서 최대 65,535바이트, PostgreSQL에서 무제한, SQL Server에서 최대 8,000바이트(더 큰 값의 경우 VARCHAR(MAX))의 길이를 지원합니다. 정확한 제한 사항은 항상 해당 데이터베이스의 설명서를 확인하세요. 적절한 유형을 선택하면 장기적인 확장성을 개선하고 예기치 않은 스토리지 한계에 도달하는 것을 방지할 수 있습니다.

데이터베이스에서 시간대는 어떻게 처리해야 하나요?

일관성과 비교 가능성을 보장하기 위해 모든 타임스탬프를 UTC로 저장하세요. 저장하기 전에 타임스탬프를 UTC로 변환하고, 표시할 때는 사용자의 로컬 시간대로 다시 변환하세요. PostgreSQL과 같은 일부 데이터베이스는 이 변환을 자동으로 처리하기 위해 TIMESTAMPTZ를 지원합니다. 일관된 시간대 처리는 시간 기반 계산의 오류를 방지하고 이벤트 순서를 명확하게 해줍니다.

고유 식별자에는 어떤 데이터 타입을 사용해야 하나요?

UUID 값은 일반적으로 고정 크기 저장 공간을 위해 BINARY(16)을 사용하거나, 하이픈을 포함한 표준 문자열 표현을 위해 CHAR(36)을 사용합니다. PostgreSQL과 같은 일부 데이터베이스는 네이티브 UUID 타입을 지원합니다. 자동 증가하는 숫자 ID에는 INT 또는 BIGINT가 적합합니다. 식별 체계에 따라 선택하세요. 순차적인 숫자 ID는 단순하지만 ID를 유추하기 쉬운 반면, UUID는 무작위적이며 분산 시스템에 적합합니다.

데이터 타입 선택이 쿼리 성능에 왜 중요한가요?

데이터 타입의 크기가 작을수록 CPU 캐시에 더 많은 행을 담을 수 있어 쿼리가 빨라집니다. 적절한 크기의 숫자 타입에서 인덱스가 더 효과적으로 작동합니다. 저장 효율성이 높아지면 디스크 I/O가 줄어들고 쿼리 대기 시간이 단축됩니다. 적절한 크기의 데이터 타입을 사용하면 쿼리 성능이 향상되며, 데이터를 안전하게 저장할 수 있는 가장 작은 타입을 선택하면 데이터베이스를 빠르고 효율적으로 유지할 수 있습니다.

(이 글은 AI의 도움을 받아 번역되었습니다. 원문이 궁금하시다면 여기를 클릭해 주세요)

최신 게시물을 이메일로 받아보세요

블로그를 구독하고 최신 게시물을 이메일로 받아보세요.