데이터 타입 비교

데이터 타입 비교 (Compare data types) (compare-data-types-2)

Redis는 아주 다양한 데이터 타입을 제공해서, 어떤 타입을 써야 할지 고민될 때가 많아요. 이 페이지에서는 각 데이터 타입의 특징과 장단점을 나란히 놓고 비교해서, 여러분의 작업에 가장 잘 맞는 타입을 고를 수 있도록 옆에서 도와드릴게요.

출처: Redis 공식 문서 — Compare data types

특수 목적 데이터 타입 (Highly specialized data types)

다음 타입들은 아주 구체적인 목적을 위해 특화되어 있어요.

일반 목적 데이터 타입 (General-purpose data types)

나머지 타입들은 좀 더 일반적인 용도로 쓰여요.

일반 목적 타입들은 기능이 조금 겹치기도 해요. 사실 문자열 하나만으로도 창의력을 발휘하면 어떤 타입이든 흉내낼 수 있을 거예요. 하지만 각 타입은 성능, 메모리 사용량, 기능 면에서 서로 다른 트레이드오프를 갖고 있죠. 이 가이드가 여러분의 작업에 가장 잘 맞는 타입을 고르는 데 도움이 될 거예요.

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

문자열 (Strings)

  • 구조: 구조화되지 않은 텍스트/바이너리 데이터, 또는 단순 카운터, 비트 집합, 정수 모음.
  • 연산: get, set, append, increment, decrement, 비트 연산.
  • 적합한 용도: 구조화되지 않은 문서, 카운터, 플래그, 비트맵.

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

배열 (Arrays)

  • 구조: 희소하고 인덱스로 접근하는 문자열 시퀀스.
  • 연산: get, set, delete, 범위 읽기, 범위 스캔, 순차 삽입, 집계.
  • 적합한 용도: 이벤트 로그, 링 버퍼, 센서 판독값, 그리고 기타 append 위주나 희소한 시퀀스.

배열은 정수 인덱스로 접근하는 값을 저장해서, 논리적 크기와 무관하게 임의 접근이 O(1)이에요. 희소 구조라서 인덱스 1,000,000에 요소를 설정해도 그 사이의 백만 개 빈 슬롯을 위한 메모리를 할당하지 않으므로, 큰 인덱스 간격도 비용이 얼마 들지 않아요. 배열은 논리적 길이(ARLEN이 반환하는, 가장 높게 설정된 인덱스 + 1)와 요소 수(ARCOUNT가 반환하는 비어 있지 않은 슬롯 수)를 구분해요.

직접 인덱스 접근 외에도 배열은 ARINSERT를 통한 순차 삽입을 지원하는데, 내부 커서가 자동으로 앞으로 나아가요. 커서는 ARSEEK으로 다시 배치할 수 있어 유연한 append 패턴이 가능하죠. ARRING은 링 버퍼 패턴을 명시적으로 만들어 줍니다. 고정 크기로 모듈로 삽입하며 버퍼가 가득 차면 가장 오래된 항목을 덮어써요. AROP은 각 요소를 개별적으로 가져오지 않고 범위에 대해 단일 패스 집계(sum, min, max, 비트 연산, 값 매칭)를 수행해요.

해시 (Hashes)

  • 구조: 키-값 쌍 모음.
  • 연산: get, set, delete, increment, decrement, 쿼리.
  • 적합한 용도: 필드 수가 적은 단순 객체.

해시는 중첩되거나 복잡하게 구조화되지 않은, 필드 수가 적은 객체를 저장하는 데 주로 유용해요. 다만 해시에 저장할 수 있는 필드 수에는 실질적 제한이 없으므로 애플리케이션 안에서 다양한 방식으로 쓸 수 있어요. 필드 값은 문자열이지만, 해시는 이를 정수나 부동소수점으로 취급해 간단한 산술 연산을 수행하는 명령도 제공해요. 개별 해시 필드에 만료 시간을 설정할 수 있고, Redis Search로 해시 문서를 인덱싱하거나 쿼리할 수도 있어요.

JSON

  • 구조: 널리 쓰이는 JSON 텍스트 파일 포맷에 맞는 계층형 배열과 키-값 객체.
  • 연산: get, set, update, delete, 쿼리.
  • 적합한 용도: 필드가 많은 복잡하고 중첩된 객체.

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

리스트 (Lists)

  • 구조: 단순한 문자열 시퀀스.
  • 연산: push, pop, get, set, trim.
  • 적합한 용도: 큐, 스택, 로그, 그리고 기타 선형 데이터 구조.

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

집합 (Sets)

  • 구조: 고유한 문자열 모음.
  • 연산: add, remove, 멤버십 테스트, intersect, union, difference.
  • 적합한 용도: 연관 데이터가 없는 고유 항목.

집합은 고유한 문자열 모음을 저장해요. 멤버십 테스트, 요소 추가·제거를 효율적으로 수행하며, 교집합, 합집합, 차집합 같은 집합 연산도 지원해요.

정렬 집합 (Sorted sets)

  • 구조: 점수와 함께 고유한 문자열 모음.
  • 연산: add, remove, 멤버십 테스트, 점수 또는 순위로 범위 조회.
  • 적합한 용도: 점수가 있는 고유 항목, 또는 정렬된 모음.

정렬 집합은 점수와 함께 고유한 문자열 모음을 저장해요. 점수 기반 효율적 범위 쿼리에 최적화되어 있어서, 우선순위 큐나 기타 정렬된 모음 구현에 유용해요.

스트림 (Streams)

  • 구조: 각 항목이 필드-값 쌍을 가지는 엔트리 시퀀스.
  • 연산: add, read, trim.
  • 적합한 용도: 로그 데이터, 시계열, 그리고 기타 append-only 구조.

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

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

아래 내용은 각 데이터 타입의 특정 작업에 대한 장단점을 다뤄요. 이 제안은 엄격한 규칙이라기보다 "경험 법칙(rules-of-thumb)"으로 봐야 해요. 특정 타입을 선호해야 하는 미묘한 이유가 얼마든지 있을 수 있으니까요.

문서 (Documents)

문서 데이터는 보통 문자열, 해시, JSON 타입으로 저장해요. 일반적으로 JSON이 메모리와 처리 요구사항이 가장 높고, 그다음이 해시, 마지막이 문자열 순이에요. 아래 의사결정 트리를 가이드로 삼아보세요.

  • 중첩 데이터 구조(필드와 배열)가 필요하거나, Redis Search로 지리공간 인덱스/쿼리를 하나? → 중첩 구조를 지원하고 Redis Search와 통합되는 유일한 문서 타입은 JSON이에요. → JSON 사용
  • Redis Search로 인덱스/쿼리는 필요한데 중첩 구조나 지리공간 인덱스는 없어도 되나? → 해시가 더 낮은 메모리 오버헤드와 더 빠른 필드 접근으로 인덱싱과 쿼리를 지원해요. → 해시 사용
  • 문서 안의 개별 데이터 조각에 만료 시간을 설정해야 하나? → 필드 레벨 접근과 만료를 효율적으로 지원하는 것은 해시뿐이에요. → 해시 사용
  • 문서 안의 개별 데이터 필드에 자주 접근해야 하는데, 그 필드가 정수 인덱스로 쉽게 참조할 수 있는 단순 정수나 비트인가? → 필드 접근은 문자열과 해시가 모두 지원하지만, 정수 인덱스의 비트 필드만 필요하다면 문자열이 더 컴팩트하고 효율적이에요. → 문자열 사용
  • 문자열이나 바이너리 값을 가진 개별 데이터 필드에 자주 접근해야 하나? → 해시가 일반적 필드 접근을 지원하지만, 그것이 필요 없다면 문자열이 더 컴팩트하고 효율적이에요. → 해시 사용
  • 그 외의 경우 → 문자열 사용

컬렉션 (Collections)

컬렉션 데이터는 보통 집합이나 정렬 집합으로 저장하고, 아주 단순한 컬렉션이라면 문자열로도 충분해요. 모두 기본적인 멤버십 테스트를 제공하지만, 추가 기능과 트레이드오프는 서로 달라요. 정렬 집합이 메모리 오버헤드와 처리 요구사항이 가장 높고, 그다음이 집합, 문자열 순이에요. 집합이나 정렬 집합의 키에 추가 정보를 저장해야 한다면, 컬렉션의 키와 이름이 일치하는 필드를 가진 보조 해시나 JSON 객체로 처리할 수 있어요.

  • 키를 임의 순서나 사전순으로 저장·검색해야 하나? → 순서 있는 반복을 지원하는 유일한 컬렉션 타입은 정렬 집합이에요. → 정렬 집합 사용
  • 각 키에 추가 정보를 저장해야 하고, 집합 연산(union, intersection, difference)은 필요 없나? → 해시가 각 키에 데이터를 연결할 수 있지만 집합 연산은 지원하지 않아요. → 해시 사용
  • 키가 항상 알려진 범위의 단순 정수 인덱스인가? → 문자열 비트맵이 정수 인덱스에 최소 메모리 오버헤드와 효율적 임의 접근을 제공하고, 집합 연산에 해당하는 비트 연산도 있어요. → 문자열(비트맵) 사용
  • 그 외의 경우 → 집합 사용

시퀀스 (Sequences)

문자열이나 바이너리 데이터의 시퀀스는 보통 정렬 집합, 리스트, 스트림, 배열로 저장해요. 각각 특정 목적에 따른 장단점이 있어요. 아래 의사결정 트리를 가이드로 삼아보세요.

  • 임의의 우선순위 순서, 사전순, 또는 집합 연산을 유지해야 하나? → 순서와 집합 연산을 모두 지원하는 유일한 시퀀스 타입은 정렬 집합이에요. → 정렬 집합 사용
  • 호출자가 고른 정수 인덱스(희소하거나 연속되지 않은 인덱스 포함)로 요소를 참조하거나, 인덱스 범위에 대한 서버 측 집계(sum, min, max, 비트 연산)를 수행하거나, 고정 크기의 링 버퍼로 가장 오래된 항목을 덮어써야 하나? → 배열은 인덱스 범위의 집계와 링 버퍼 연산을 제공하며, 리스트와 스트림은 이 기능이 없어요. → 배열 사용
  • 요소를 주로 타임스탬프 순서로 저장·검색하거나, 시퀀스를 읽는 여러 소비자를 관리해야 하나? → 타임스탬프 기반 순서와 at-least-once 전달의 소비자 그룹을 지원하는 유일한 시퀀스 타입은 스트림이에요. → 스트림 사용
  • 그 외의 경우 → 리스트 사용

더 알아보기 (Learn more)