데이터 타입 비교하기

데이터 타입 비교하기 (Compare data types)

어떤 작업에 어떤 Redis 데이터 타입을 써야 할지 고민될 때가 있죠. 이 페이지는 각 데이터 타입의 특징과 장단점을 정리해서, 여러분의 작업에 맞는 최선의 타입을 고르는 데 도움을 주는 가이드예요.

출처: Redis 공식 문서 — compare-data-types

데이터 타입 선택의 기본 원칙

Redis는 다양한 작업을 위한 여러 가지 데이터 타입을 제공해요. 어떤 타입이 어떤 용도에 맞는지 먼저 큰 그림으로 살펴볼게요.

일반 목적 데이터 타입은 특성이 서로 겹치는 부분이 있어요. 사실 문자열(string)과 약간의 창의력만 있으면 어떤 타입이든 흉내낼 수 있죠. 그런데 각 데이터 타입은 성능, 메모리 사용, 기능 면에서 서로 다른 tradeoff를 제공해요. 그래서 용도에 맞는 타입을 고르는 게 중요해요.

데이터 타입 특징 (Data type features)

Strings (문자열)

  • 구조: 구조화되지 않은 텍스트/바이너리 데이터, 또는 단순 카운터, 비트 세트, 정수 컬렉션
  • 연산: get, set, append, increment, decrement, 비트 단위 연산
  • 적합한 경우: 구조화되지 않은 문서, 카운터, 플래그, 비트맵

문자열은 주로 내부 구조를 애플리케이션이 직접 관리하는 텍스트나 바이너리 데이터 묶음을 저장하는 데 유용해요. 또한 문자열 안의 비트 범위에 접근해 비트 세트, 정수, 부동소수점으로 활용하는 연산도 지원해요.

Arrays (배열)

  • 구조: 희소(sparse)하고 인덱스로 주소 지정이 가능한 문자열 시퀀스
  • 연산: get, set, delete, 범위 읽기, 범위 스캔, 순차 삽입, 집계(aggregate)
  • 적합한 경우: 이벤트 로그, 링 버퍼, 센서 판독값, 그리고 append-heavy 또는 희소 시퀀스

배열은 정수 인덱스로 주소가 지정되는 값을 저장해요. 그래서 논리적 크기와 무관하게 임의 접근이 O(1)이에요. 배열이 희소(sparse)하기 때문에 1,000,000번째 인덱스에 요소를 설정해도 그 사이 100만 개의 빈 슬롯을 위한 메모리를 할당하지 않아요. 그래서 큰 인덱스 간격은 비용이 거의 들지 않죠.

배열은 논리적 길이(가장 높게 설정된 인덱스 + 1, ARLEN이 반환)와 요소 개수(비어있지 않은 슬롯 수, ARCOUNT가 반환)를 구분해요. 직접 인덱스 접근 외에도 ARINSERT로 내부 커서를 자동으로 전진시키며 순차 삽입할 수 있고, ARSEEK로 커서를 다시 위치시킬 수 있어요. ARRING은 고정 크기로 modulo 삽입하며 버퍼가 가득 차면 가장 오래된 항목을 덮어쓰는 링 버퍼 패턴을 명시적으로 제공하고, AROP은 각 요소를 개별적으로 가져오지 않고 범위에 대해 단일 패스 집계(sum, min, max, 비트 연산, 값 매칭)를 수행해요.

Hashes (해시)

  • 구조: 키-값 쌍의 컬렉션
  • 연산: get, set, delete, increment, decrement, query
  • 적합한 경우: 필드 수가 적은 단순 객체

필드 값은 문자열이지만, 해시는 그것들을 정수나 부동소수점으로 취급해 간단한 산술 연산을 수행하는 명령어를 제공해요. 개별 해시 필드에 만료 시간을 설정할 수도 있고, 해시 문서를 인덱싱하고 쿼리할 수도 있어요.

JSON

  • 구조: 널리 쓰이는 JSON 텍스트 파일 포맷과 일치하는 계층적 배열과 키-값 객체
  • 연산: get, set, update, delete, query
  • 적합한 경우: 많은 필드를 가진 복잡하고 중첩된 객체

JSON은 중첩된 필드와 배열로 풍부한 데이터 모델링 기능을 제공해요. 간단한 경로(path) 문법으로 JSON 문서 안의 데이터 일부에 접근할 수 있죠. JSON은 해시보다 더 강력하고 유연한 Redis Search 기능도 갖고 있어요.

Lists (리스트)

  • 구조: 문자열의 단순 시퀀스
  • 연산: push, pop, get, set, trim
  • 적합한 경우: 큐, 스택, 로그 및 기타 선형 데이터 구조

리스트는 문자열 값의 시퀀스를 저장해요. 머리(head)나 꼬리(tail)에서 적은 수의 요소를 추가·제거하는 데 최적화되어 있어서 큐, 스택, deque(데크)를 구현하는 데 매우 효율적이에요.

Sets (셋)

  • 구조: 고유 문자열의 컬렉션
  • 연산: add, remove, 멤버십 테스트, 교집합, 합집합, 차집합
  • 적합한 경우: 연관 데이터가 없는 고유 항목

셋은 고유 문자열의 컬렉션을 저장해요. 멤버십 테스트, 요소 추가·제거를 위한 효율적인 연산을 제공하고, 교집합·합집합·차집합 같은 집합 연산도 지원해요.

Sorted sets (정렬된 셋)

  • 구조: 연관된 점수(score)를 가진 고유 문자열의 컬렉션
  • 연산: add, remove, 멤버십 테스트, 점수 또는 순위로 범위 조회
  • 적합한 경우: 점수를 가진 고유 항목, 또는 정렬된 컬렉션

정렬된 셋은 점수와 함께 고유 문자열의 컬렉션을 저장해요. 점수 기반의 범위 쿼리에 최적화되어 있어서 우선순위 큐(priority queue)나 기타 정렬된 컬렉션을 구현하는 데 유용해요.

Streams (스트림)

  • 구조: 각각 필드-값 쌍을 가진 항목(entry)들의 시퀀스
  • 연산: add, read, trim
  • 적합한 경우: 로그 데이터, 시계열, 기타 append-only 구조

스트림은 각 항목이 필드-값 쌍을 가진 항목들의 시퀀스를 저장해요. 새 항목을 추가하고 순서대로 읽는 데 최적화되어 있어서 로그 데이터, 시계열, 기타 append-only 데이터 구조를 구현하는 데 유용해요. 또한 소비자 그룹(consumer groups)을 기본 지원해요.

데이터 타입 고르기 (Choose a data type)

문서 (Documents)

문서 데이터는 보통 문자열(string), 해시(hash), JSON 타입으로 저장해요. 메모리와 처리 요구사항은 JSON이 가장 높고, 그다음 해시, 그다음 문자열 순이에요. 아래 의사결정 트리를 가이드 삼아 작업에 맞는 최선의 타입을 골라보세요.

중첩된 데이터 구조(필드와 배열)나 Redis Search를 이용한
지리공간 인덱스/쿼리가 필요한가?
├── 예 → JSON 사용
└── 아니오 → Redis Search로 인덱스/쿼리는 필요하지만
             중첩 구조와 지리공간 인덱스는 필요 없는가?
    ├── 예 → 해시 사용
    └── 아니오 → 문서 안 개별 데이터에 만료 시간을 설정해야 하는가?
        ├── 예 → 해시 사용
        └── 아니오 → 문서 안 개별 필드에 자주 접근하되, 그 필드가
                     정수 인덱스로 참조하기 쉬운 단순 정수나 비트인가?
            ├── 예 → 문자열 사용
            └── 아니오 → 문자열/바이너리 값인 개별 필드에 자주 접근하는가?
                ├── 예 → 해시 사용
                └── 아니오 → 문자열 사용

컬렉션 (Collections)

컬렉션 데이터는 보통 set 또는 sorted set 타입으로 저장해요. 아주 단순한 컬렉션이라면 문자열도 쓸 수 있어요. 모두 기본 멤버십 테스트를 허용하지만, 각각 추가 기능과 tradeoff가 달라요. 메모리 오버헤드와 처리 요구사항은 sorted set이 가장 높고, 그다음 set 순이에요.

고유 항목 컬렉션이 필요한가?
├── 예 → 정렬이 필요한가?
│   ├── 예 → 정렬된 셋 사용
│   └── 아니오 → 메모리를 아끼면서 큰 컬렉션의 멤버십을 저장해야 하나?
│       ├── 예 → 문자열 사용 (비트맵)
│       └── 아니오 → 셋 사용
└── 아니오 → (많은 경우 자연스럽게 다른 타입 선택으로 이어져요)

의사결정 트리의 정확한 분기는 원문의 interactive decision-tree를 바탕으로 요약한 것이며, 세부 조건이 바뀔 수 있어요. 자세한 내용은 원문을 확인해 주세요 — 일부 지점은 '확인 필요'로 표시할게요.

더 알아보기 (Learn more)