
레디스를 효과적으로 사용하려면 자료형을 뺴놓을 수 없습니다. 이 포스트에서는 여러 자료형의 실행 예시, 관련 명령어, 특징과 유스케이스 등을 다루고, 더 나아가 자료형의 내부 인코딩 및 복잡도를 설명합니다.
레디스에는 여러가지 자료형이 있지만 대표적으로 다섯 가지를 꼽을 수 있습니다.
레디스를 잘 활용하려면 자료형을 꼭 이해해야 합니다. 데이터 모델에 맞는 적절한 자료형을 선택해야 애플리케이션을 더 간단하게 구현하면서도 성능을 끌어낼 수 있습니다.
레디스의 주요 자료형에는 String형, List형, Hash형, Set형, Sorted Set형이 있습니다.
| 자료형 | 설명 | 사용 예시 |
|---|---|---|
| String형 | 문자열(레디스에서는 숫자값도 포함) | 세션 정보관리 |
| List형 | 리스트, 문자열 리스트다 | 타임라인 |
| Hash형 | 해시, 프로그래밍 언어에서 연관 배열과 같다 | 객체 표현 |
| Set형 | 집합, 중복이 허용되지 않는 집합형 자료구조 | 태그 관리 |
| Sorted Set형 | 정렬된 집합, 순서(랭킹)가 있는 집합형 자료구조 | 랭킹 |
레디스는 대표적으로 다섯 가지 자료형이 있고, 각 자료형 별로 데이터를 다루는 체계를 갖추고 있습니다. 그러나 그와는 별개로 기본 자료형 내부에서 특정 용도에 사용될 목적으로 만들어진 보조 자료형도 있습니다:
또한 '데이터를 어떻게 활용할 것인가?' 라는 관점에서 다음과 같이 데이터를 직접 다루는 기능도 갖추고 있습니다. 이 기능들은 자료형처럼 데이터를 어떻게 표현하는지보다는 데이터를 어떻게 활용할지에 중점을 두고 있습니다.
레디스는 특정 문제가 발생했을 때 해당 문제에 맞춰 적합한 자료형을 선택하면 데이터를 간단하게 다룰 수 있다는 장점이 있습니다.
예를 들면, 레디스는 키와 값의 쌍을 억지로 조합해 복잡한 데이터를 저장할 수 있습니다. 하지만 그렇게 하면 애플리케이션 로직이 복잡해지며, 원자적 처리를 보장할 수 없는 등의 문제를 야기할 수 있습니다. 이런 상황을 대비하기 위해 레디스는 다양한 선택지를 제공하며, 개발자는 유스케이스에 맞는 자료형을 사용해야 합니다.
레디스에서 데이터는 어떻게 조작할까요?
레디스는 데이터 구조 저장소이고, 키에 값을 저장하는 것이 기본 개념입니다. 자료형이 다양하다는 차이가 있지만 접근 방식 자체는 간단한 키-값 저장소와 비슷합니다.
기본적으로 저장할 때 키에 값을 지정하고, 값을 불러올 때는 키와 다른 옵션을 조합합니다.
명령어는 '모든 자료형에서 사용할 수 있는 것' 과 '여러 자료형이나 기능별로 사용할 수 있는 것' 이 있습니다.
데이터를 저장하고 가져올 때는 기본적으로 데이터별 독립된 명령어를 사용합니다. 예를 들어, String 자료형에서는
SET으로 저장하고GET으로 가져옵니다.127.0.0.1:6379> SET USER_X 100 OK 127.0.0.1:6379> GET USER_X "100"
다른 자료형 관련 명령어는 사용할 수 없습니다. Hash형 자료형에
HSET을 사용해USER라는 키에 데이터를 저장해도,GET으로 데이터를 가져올 수 없습니다.127.0.0.1:6379> HSET USER USER_ID 100 USER_LEVEL 99 (integer) 2 127.0.0.1:6379> GET USER (error) WRONGTYPE Operation against a key holding the wrong kind of value
데이터를 저장하고 가져올 때, 여러 개의 키를 동시에 조작할 수 있는 명령어도 있습니다. 예를 들어, String 형에서 하나의 키를 조작하기 위해서는
SET으로 저장하고,GET으로 가져올 수 있습니다. 여러 키를 동시에 조작하기 위해서는MSET,MGET명령어를 사용할 수 있으며, 원자적으로 처리합니다.127.0.0.1:6379> HSET USER USER_ID 100 USER_LEVEL 99 (integer) 2 127.0.0.1:6379> GET USER (error) WRONGTYPE Operation against a key holding the wrong kind of value
💡명령어는 대소문자를 구별하지 않지만, 공식문저는 대문자로 기재되어 있습니다. 단, 키와 값은 대소문자를 구별합니다.
레디스에서 제공하는 명령어 중, 디버그 등의 용도로 많이 사용되는 명령어는 다음과 같습니다:
KEYSEXISTSTYPEDEL레디스에서 키 목록을 확인하고 싶을 때는
KEYS명령어를 사용합니다. 아래 예시처럼 패턴으로 검색 대상을 제한합니다.KEYS pattern패턴에는 와일드카드를 사용할 수 있습니다. 모든 키를 표시하고자 할 경우에는 *를 사용합니다.
127.0.0.1:6379> KEYS * "USER_Y" "USER" "mykey" "foo" "USER_X" "USER_Z"⛔️
KEYS명령어는 편리하지만 패턴을 쓰든 안쓰든 키 전체를 스캔하기 때문에 실행 시간이 오래 걸립니다. 실제 운용 중인 애플리케이션에서 쉽게 시용해서는 안 됩니다.
운영 환경에서는SCAN계열의 명령어를 사용해야합니다.
EXISTS key [keys...]인수에 해당하는 키가 존재하면 1을, 존재하지 않으면 0을 반환합니다. 키가 여러 개 있는 경우 매칭된 수를 반환합니다.
127.0.0.1:6379> SET X valueX OK 127.0.0.1:6379> EXISTS X (integer) 1 127.0.0.1:6379> EXISTS Y (integer) 0 127.0.0.1:6379> EXISTS X Y (integer) 1 127.0.0.1:6379> SET Z valueZ OK 127.0.0.1:6379> EXISTS X Y Z (integer) 2
TYPE명령어로 자료형과 기능을 확인할 수 있습니다.127.0.0.1:6379> SET mykey myvalue OK 127.0.0.1:6379> HSET myhash myfield myvalue (integer) 1 127.0.0.1:6379> TYPE mykey string 127.0.0.1:6379> TYPE myhash hash
키의 삭제는 모든 자료형에서 공통적으로
DEL을 사용합니다. 반환되는 값을 삭제한 키의 개수입니다.DEL key [key...]
String형은 문자열, 이진 데이터 등을 위한 자료형입니다. String형이란 이름을 붙였지만, 이진 안전 문자열이기 때문에 이미지나 실행파일 등 문자열 이외의 데이터도 저장할 수 있습니다.
심지어 레디스에서는 숫자값(정수나 부동소수점)도 String형에 저장합니다.
String형에 저장한 부동소수점을 조작하기 위한 전용 명령어(INCRBYFLOAT)도 있습니다.
String형에는 Bitmap형이라는 비트 단위로 조작할 수 있는 보조자료형이 존재합니다. Bitmap형은 실제 자료형은 아니며, String형에 의해 정의된 것입니다.
String형은 값을 저장할 때 SET, 값을 불러올 때 GET을 사용합니다. 각 사용법은 SET key value와 GET key형태로 사용합니다.
존재하는 키에 쓰기 작업을 수행하면, 기본적으로 덮어쓰게 됩니다.
String형은 숫자값도 저장할 수 있습니다. 또한 같은 String형이더라도 저장한 값의 종류에 따라 사용할 수 있는 명령어가 다를 수 있습니다.
예를 들어, String형에 숫자값을 저장한 경우에는 숫자 증가 명령어는 INCR를 사용할 수 있습니다.
127.0.0.1:6379> SET HIT_COUNT 100 OK 127.0.0.1:6379> TYPE HIT_COUNT string 127.0.0.1:6379> INCR HIT_COUNT (integer) 101
String형 명령어는 값의 내용과 관계없이 사용할 수 있는 것과 값이 숫자일 경우에만 사용할 수 있는 것으로 나눌 수 있습니다.
redis 공식 문서 에서는 관련 명령어와 함께 시간복잡도까지 확인할 수 있습니다.
아래에서 주요 명령어를 정리해보겠습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| GET | 지정한 키의 값을 가져옴 | GET mykey |
| SET | 키에 값을 저장하거나 기존 값을 덮어씀 | SET mykey "hello" |
| MGET | 여러 키의 값을 한 번에 가져옴 | MGET key1 key2 |
| MSET | 여러 키에 값을 한 번에 저장함 | MSET key1 "a" key2 "b" |
| APPEND | 기존 키의 문자열 값에 새로운 문자열을 덧붙임 | APPEND mykey " world" |
| STRLEN | 문자열 값의 길이를 반환함 | STRLEN mykey |
| GETRANGE | 문자열 값의 특정 범위(인덱스) 부분을 가져옴 | GETRANGE mykey 0 4 |
| SETRANGE | 문자열 값의 특정 위치를 기준으로 일부를 덮어씀 | SETRANGE mykey 6 "Redis" |
추가로, 아래에서는 값이 숫자인 경우에만 사용할 수 있는 명령어들입니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| INCR | 키의 값을 1만큼 증가시킴 | INCR counter |
| INCRBY | 키의 값을 지정한 정수만큼 증가시킴 | INCRBY counter 5 |
| INCRBYFLOAT | 키의 값을 지정한 부동소수점 수만큼 증가시킴 | INCRBYFLOAT score 1.5 |
| DECR | 키의 값을 1만큼 감소시킴 | DECR counter |
| DECRBY | 키의 값을 지정한 정수만큼 감소시킴 | DECRBY counter 3 |
SETEX명령어를 사용하면 키에 값을 설정하면서 동시에 TTL도 설정할 수 있습니다. 다음은 설정 후 TTL 명령어로 키의 남은 TTL을 확인하는 예시입니다.127.0.0.1:6379> SETEX msg:7 300 "Hello World" OK 127.0.0.1:6379> TTL msg:7 (integer) 297
SET명령어를 실행한 후,EXPIRE명령어를 실행해도 동일한 결과를 얻을 수 있습니다.127.0.0.1:6379> SET msg:7 "Hello World" OK 127.0.0.1:6379> EXPIRE msg:7 300 (integer) 1 127.0.0.1:6379> TTL user:7 (integer) 297또는 아래처럼
SET명령어의EX옵션을 사용할 수도 있습니다.127.0.0.1:6379> SET msg:7 "Hello World" EX 300 OK 127.0.0.1:6379> TTL msg:7 (integer) 297
💡원자적으로 동작하기를 원한다면
SETEX,EX명령어를 사용해야합니다.
SET 명령어와 옵션SET 명령어에서 사용 가능한 옵션은 다음과 같습니다:
EX/PX: TTL이라고 하는 만료 시간을 설정합니다.
EX: 초 단위PX: 밀리 초 단위NX/XX: 키의 존재 여부에 따라 조건을 충족할 때만 저장합니다.
NX는 키가 존재하지 않는 경우, XX는 키가 존재하는 경우에만 저장합니다.KEEPTTL: 키 관련 TTL을 변경하지 않고 조작합니다
EXAT/PXAT: 키를 지정하여 값을 가져온 후 계속해서 설정을 수행합니다.
⚠️
EXAT/PXAT옵션을 사용하는 경우에는 설정한 TTL이 NTP(Network TIme Protocol)의 시간 동기화 영향을 받으므로 시간 동기 상태에 주의해야 합니다.
List형은 문자열(레디스의 String형 값)의 리스트입니다. 리스트의 키는 여러 값을 순서대로 저장할 수 있습니다. 값을 삽입한 순서대로 유지하는 자료형이며, 스택이나 큐 등으로 사용하기 좋습니다.
리스트의 맨 앞, 맨 뒤에 데이터를 추가하거나 제거하는 것은 상수 시간으로 처리가 가능하지만, 중간에 있는 값은 리스트의 자료구조적 특성으로 인해 오래 걸릴 수 있습니다.
값을 저장하는 주요 명령어는 다음과 같습니다:
LPUSH: 맨 왼쪽에 값을 추가RPUSH: 맨 오른쪽에 값을 추가값을 가져오는 주요 명령으로는 범위를 지정해 요소를 반환하는 LRANGE가 있습니다.
다음예시는 LRANGE 명령어로 리스트 왼쪽부터 지정한 범위의 데이터를 꺼냅니다.
127.0.0.1:6379> LPUSH mylist foo bar baz (integer) 3 127.0.0.1:6379> LRANGE mylist 0 -1 1) "baz" 2) "bar" 3) "foo"0은 리스트의 처음부터 값을 가져오는 것을 의미하고, -1은 리스트의 마지막을 의미합니다.
인기 콘텐츠를 표시하는 기능은 웹 애플리케이션에서 자주 사용되며, Redis의 List형을 활용하면 간단하게 구현할 수 있습니다. 예를 들어, "최근 인기 콘텐츠"를 시간 순서대로 유지하는 타임라인 형태로 저장할 수 있습니다. 사용자가 콘텐츠를 조회하거나 좋아요를 누를 때마다 해당 콘텐츠를 리스트에 추가(또는 업데이트)하여, 가장 최근에 인기 있는 콘텐츠를 맨 앞에 배치합니다. List형의 장점은 삽입/제거가 O(1) 시간 복잡도로 빠르다는 점입니다. List형을 어떻게 활용할지 감을 잡기 위해, 예시를 들어보겠습니다.
유스케이스 설명
실행 예시 (Redis CLI)
아래는 "popular_contents"라는 키로 List를 생성하고 관리하는 예시입니다. 콘텐츠 ID를 문자열로 저장한다고 가정합니다.
초기 리스트 생성: 최근 인기 콘텐츠 추가 (맨 앞에 최신 콘텐츠)
127.0.0.1:6379> LPUSH popular_contents "content_id_101" "content_id_102" "content_id_103" (integer) 3
리스트 조회 (0부터 -1까지: 전체)
127.0.0.1:6379> LRANGE popular_contents 0 -1 1) "content_id_103" # 가장 최근 (맨 앞) 2) "content_id_102" 3) "content_id_101" # 가장 오래된 (맨 뒤)
새로운 인기 콘텐츠 추가 (맨 앞에 푸시)
127.0.0.1:6379> LPUSH popular_contents "content_id_104" (integer) 4
리스트 조회 (변경 후)
127.0.0.1:6379> LRANGE popular_contents 0 -1 1) "content_id_104" 2) "content_id_103" 3) "content_id_102" 4) "content_id_101"
리스트 길이 제한: Top 3만 유지 (오래된 항목 자동 제거)
127.0.0.1:6379> LTRIM popular_contents 0 2 OK
제한 후 조회
127.0.0.1:6379> LRANGE popular_contents 0 -1 1) "content_id_104" 2) "content_id_103" 3) "content_id_102"
콘텐츠 제거 예시 (특정 값 제거, 필요 시)
127.0.0.1:6379> LREM popular_contents 1 "content_id_103" # 1회 제거 (integer) 1
최종 조회
127.0.0.1:6379> LRANGE popular_contents 0 -1 1) "content_id_104" 2) "content_id_102"
주의사항
List에서 사용 가능한 주요 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| LPUSH | 리스트 왼쪽(앞)에 하나 이상 값을 추가 | LPUSH mylist a b c |
| RPUSH | 리스트 오른쪽(뒤)에 하나 이상 값을 추가 | RPUSH mylist x y |
| LPOP | 리스트 왼쪽(앞)에서 요소를 하나 꺼냄 | LPOP mylist |
| RPOP | 리스트 오른쪽(뒤)에서 요소를 하나 꺼냄 | RPOP mylist |
| LMPOP | 여러 리스트 중 하나를 선택해 좌/우에서 여러 개 꺼냄 | LMPOP 2 mylist1 mylist2 LEFT COUNT 3 |
| BLMPOP | LMPOP의 블로킹 버전(타임아웃 내 요소가 생길 때까지 대기) | BLMPOP 5 2 mylist1 mylist2 RIGHT COUNT 2 |
| LINDEX | 지정한 인덱스의 요소를 조회(0부터 시작, 음수는 뒤에서) | LINDEX mylist 0 |
| LINSERT | 기준 값(pivot) 앞/뒤에 새 요소 삽입 | LINSERT mylist BEFORE "pivot" "new" |
| LLEN | 리스트 길이(요소 수)를 반환 | LLEN mylist |
| LRANGE | 지정한 범위의 요소들을 조회 | LRANGE mylist 0 -1 |
| LREM | 주어진 값과 일치하는 요소를 count만큼 제거(방향 포함) | LREM mylist 2 "foo" |
| LSET | 지정한 인덱스 위치의 값을 변경 | LSET mylist 0 "new" |
| LTRIM | 지정한 범위만 남기고 나머지 요소를 잘라내어 삭제 | LTRIM mylist 0 9 |
| LPOS | 리스트에서 특정 값의 인덱스를 반환(옵션: RANK, MAXLEN 등) | LPOS mylist "foo" RANK 2 |
Hash형은 순서 없이 필드와 값이 여러 쌍으로 매핑된 자료구조입니다. 마치 프로그래밍 언어의 연관 배열이나 딕셔너리 같은 자료구조를 떠올리면 됩니다.
실행 예시를 보겠습니다. Hash형은 특정 객체(Object)를 값으로 다룹니다. 여기서는 myhash라는 사용자 객체를 가리키는 키에 필드와 값의 조합을 HSET명령어로 저장합니다. 그리고 myhash에서 이름 정보를 꺼내오기 위해서 field1 필드 정보의 값을 HGET 명령어로 가져옵니다.
필드 값 field1 value1 field2 value2 field3 value3 127.0.0.1:6379> HSET myhash field1 value1 field2 value2 field3 value3 (integer) 3 127.0.0.1:6379> HGET myhash field1 value1
다음으로는 기존에 String 으로 관리되던 데이터를 Hash로 어떻게 전환할 수 있는지 예시를 통해 확인해보겠습니다.
SET user:1:name "Minseok Choi" SET user:1:age 28이러한 경우 하나의 Hash 형으로 관리하면 메모리를 효율적으로 사용할 수 있습니다. 다음과 같이 말이지요:
HSET user:1 name "Minseok Choi" age 28
레디스는 객체 스토리지로 사용할 수 있습니다. 상품 정보를 저장할 때 상품 이름이나 가격 등 여러 속성이 있는 객체 스토리지의 경우에는 레디스의 Hash형을 사용하면 쉽게 구현할 수 있습니다.
Hash형의 주요 명령어를 살펴봅시다.
Hash형은 String형과 마찬가지로 필드값이 숫자인 경우에 사용할 수 있는 명령어와 값 내용에 상관없이 사용할 수 있는 명령어가 있습니다.
값에 상관 없이 사용할 수 있는 주요 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| HDEL | 하나 이상의 필드를 삭제 | HDEL myhash field1 field2 |
| HEXISTS | 특정 필드 존재 여부 확인 | HEXISTS myhash field1 |
| HGET | 특정 필드의 값을 조회 | HGET myhash field1 |
| HGETALL | 모든 필드와 값을 조회 | HGETALL myhash |
| HKEYS | 모든 필드 이름만 조회 | HKEYS myhash |
| HLEN | 필드의 개수(해시 크기) 조회 | HLEN myhash |
| HMSET | 여러 필드를 한 번에 설정(신규/덮어쓰기, deprecated) | HMSET myhash field1 v1 field2 v2 |
| HSET | 한 개 또는 여러 필드를 설정(신규/덮어쓰기) | HSET myhash field1 v1 field2 v2 |
| HVALS | 모든 값만 조회 | HVALS myhash |
| HSCAN | 커서 기반으로 필드-값을 점진적으로 순회 | HSCAN myhash 0 MATCH name* COUNT 10 |
값이 숫자인 경우에 사용할 수 있는 주요 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| HINCRBY | 지정한 필드의 정수값을 증감(음수 가능) | HINCRBY myhash age 1 |
| HINCRBYFLOAT | 지정한 필드의 부동소수점 값을 증감 | HINCRBYFLOAT myhash score 0.5 |
유스케이스에 따라서는 Hash형보다 String형을 사용하는게 더 나은 경우도 있습니다. 실수하기 쉬운 내용에 대해 다뤄보겠습니다.
1. 해시 요소의 개수가 많거나 최대 요소의 개수가 큰 경우
하나의 해시에 들어가는 요소의 개수가 많거나, 최대로 가질 수 있는 요소의 개수가 큰 경우에는 Hash형의 장점인
내부 인코딩의 메모리 압축을 제대로 확용하지 못합니다.
이런 경우에는 내부 인코딩 관련 매개변수를 조정하여 메모리 압축을 더 효과적으로 하거나, String형의 사용을 검토해야 합니다.
2. 해시 전체 크기가 너무 큰 경우
하나의 해시 전체 크기가 크면, 레디스 클러스터 사용 시 샤드 간 데이터 분산이 어려워질 수 있습니다. 이 경우에는 String형 키를 사용하여 세부적으로 관리하면 확장이 쉬워질 수 있습니다.
3. HDEL 명령어 실행 시간
키로 지정한 해시가 필드 수 증가 등으로 커졌을 경우, HDEL 명령어를 실행하면 수행 시간이 길어져 다른 명령어가 블록될 수 있습니다.
HDEL 명령어는 해시 내의 필드 수를 N이라 할 때, 시간 복잡도가 O(N)입니다. 즉, 시간 복잡도가 필드 수에 비례합니다.
스키마 설계에 따라서는 HDEL 명령어를 꼭 사용해야 하는 경우도 있습니다. 이 경우에는 문제를 해결하려면 설계를 다시 해야합니다. 따라서 사전에 벤치마크를 수행하고 해시를 더 작은 단위로 분할할 수 없는지, String형으로 처리하는 건 어떤지 등을 고려해야 합니다.
Set형은 문자열의 집합입니다. 집합의 키는 여러 값을 순서와 중복 없이 저장할 수 있습니다.
같은 값을 여러 번 저장해도 하나의 값으로 저장됩니다.
다음은 Set형에 myset이라는 키 이름을 집합으로 하고 member1, member2, member3라는 멤버를 SADD 명령어로 추가하는 예시입니다.
127.0.0.1:6379> SADD myset member1 member2 member3
(integer) 3
그 후 SMEMBERS 명령어로 집합에 멤버 목록을 확인합니다.
127.0.0.1:6379>> SMEMBERS myset
1) "member3"
2) "member1"
3) "member2"
어떤 집합의 요소 개수를 카운트할 때 Set형을 사용한다면 데이터 세트의 크기에 비례하여 소비하는 메모리 양도 증가합니다. 그 경우 다소 오차를 허용해도 괜찮다면 HyperLogLog기능을 활용할 수 있습니다.
Set 명령어 중 자주 사용되는 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| SADD | 집합에 하나 이상의 멤버 추가 | SADD myset member1 member2 |
| SCARD | 집합에 포함된 멤버의 개수 반환 | SCARD myset |
| SISMEMBER | 특정 멤버가 집합에 존재하는지 확인 | SISMEMBER myset member1 |
| SMEMBERS | 집합의 모든 멤버 조회 | SMEMBERS myset |
| SPOP | 집합에서 무작위로 하나 또는 여러 멤버를 제거 후 반환 | SPOP myset 2 |
| SREM | 집합에서 특정 멤버 제거 | SREM myset member1 |
| SSCAN | 커서 기반으로 집합을 점진적으로 순회 | SSCAN myset 0 MATCH mem* COUNT 10 |
Set형에서 사용 가능한 집합 연산 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| SDIFF | 집합들의 차집합 반환 (첫 번째 집합 − 나머지) | SDIFF set1 set2 set3 |
| SDIFFSTORE | 차집합을 계산하여 새 집합 키에 저장 | SDIFFSTORE result set1 set2 set3 |
| SINTER | 교집합 반환 | SINTER set1 set2 |
| SINTERSTORE | 교집합을 계산하여 새 집합 키에 저장 | SINTERSTORE result set1 set2 |
| SINTERCARD | 교집합의 **원소 개수(카디널리티)**만 반환 | SINTERCARD 3 set1 set2 set3 |
| SUNION | 합집합 반환 | SUNION set1 set2 set3 |
| SUNIONSTORE | 합집합을 계산하여 새 집합 키에 저장 | SUNIONSTORE result set1 set2 set3 |
Sorted Set형은 이름에서 알 수 있듯 순서가 있는 Set형입니다. 실시간 랭킹에 활용하는 경우가 많으며 레디스의 특징이라고도 할 수 있는 자료형입니다.
Sorted Set의 각 키는 고유한 값으로, 점수로 정렬된 순서 집합입니다. Sorted Set의 각 값은 항상 부동소숫점 숫자이며, 정수를 넣어도 부동소숫점으로 변환됩니다. 문자열은 넣을 수 없습니다.
Sorted Set에서 사용할 수 있는 주요 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| ZADD | 멤버를 점수와 함께 추가/갱신 | ZADD rank 120 user:a 150 user:b |
| ZCARD | 집합의 멤버 수(카디널리티) | ZCARD rank |
| ZRANK | 오름차순 기준 랭크(0부터, 점수 낮을수록 앞) | ZRANK rank user:a |
| ZREVRANK | 내림차순 기준 랭크(0부터, 점수 높을수록 앞) | ZREVRANK rank user:b |
| ZRANGE | 범위 조회(인덱스/점수/사전순 기준 가능, WITHSCORES 지원) |
ZRANGE rank 0 9 REV WITHSCORES |
| ZRANGESTORE | ZRANGE 결과를 다른 키에 저장 | ZRANGESTORE top10 rank 0 9 REV |
| ZREM | 하나 이상의 멤버 제거 | ZREM rank user:x user:y |
| ZCOUNT | 점수 구간에 해당하는 멤버 수 | ZCOUNT rank 100 200 |
| ZPOPMAX | 가장 점수 큰 멤버(들) 꺼내서 반환+삭제 | ZPOPMAX rank 3 |
| ZPOPMIN | 가장 점수 작은 멤버(들) 꺼내서 반환+삭제 | ZPOPMIN rank 2 |
| ZSCORE | 특정 멤버의 점수 조회 | ZSCORE rank user:a |
| ZMSCORE | 여러 멤버의 점수 한번에 조회 | ZMSCORE rank user:a user:b |
| ZSCAN | 커서 기반 순회(대량 키에서 점진적 스캔) | ZSCAN rank 0 MATCH user:* COUNT 50 |
| ZMPOP | 여러 Sorted Set 중 하나를 골라 좌/우에서 팝 | ZMPOP 2 rank1 rank2 MAX COUNT 5 |
| BZMPOP | ZMPOP의 블로킹 버전(타임아웃까지 대기) |
BZMPOP 5 2 rank1 rank2 MIN COUNT 2 |
Sorted Set에서 사용 가능한 집합 연산 명령어는 다음과 같습니다:
| 명령어 | 용도 | 사용 예시 |
|---|---|---|
| ZINTER | 여러 Sorted Set의 교집합을 반환 (점수는 기본 합계) | ZINTER 2 zset1 zset2 WITHSCORES |
| ZINTERSTORE | 교집합을 계산해 새 키에 저장 (WEIGHTS, AGGREGATE 지원) |
ZINTERSTORE out 2 zset1 zset2 WEIGHTS 1 2 AGGREGATE MAX |
| ZINTERCARD | 교집합의 **원소 개수(카디널리티)**만 반환 (옵션: LIMIT) |
ZINTERCARD 3 zset1 zset2 zset3 LIMIT 1000 |
| ZDIFF | 첫 번째 집합에서 나머지를 뺀 차집합 반환 | ZDIFF 3 zset1 zset2 zset3 WITHSCORES |
| ZDIFFSTORE | 차집합을 계산해 새 키에 저장 | ZDIFFSTORE result zset1 zset2 |
| ZUNION | 여러 Sorted Set의 합집합 반환 (겹치는 멤버는 점수 집계) | ZUNION 3 zset1 zset2 zset3 WITHSCORES |
| ZUNIONSTORE | 합집합을 계산해 새 키에 저장 (WEIGHTS, AGGREGATE 지원) |
ZUNIONSTORE out 2 zset1 zset2 WEIGHTS 1 0.5 AGGREGATE SUM |
Redis에서 제공하는 여러가지 기능들에 대해서는 다음 포스트에서 살펴보겠습니다.