Redis + SQL


  데이터의 새로운 발견  

레디스 Key-Value 데이터를
SQL SELECT로 조회할 수 있습니다.


  데이터 활용이 획기적으로 향상되었습니다.


형식: SELECT * FROM DATATYPE.KEY*
  예  : SELECT * FROM STRING.KEY*

  • SELECT의 컬럼은 key, value입니다. ZSet일 경우 Score 컬럼이 추가됩니다.
  • Table 부분은 Datatype.key로 구성됩니다.
  • Datatype은 String, List, Set, ZSet, Hash, Stream를 사용할 수 있습니다.
  • Key는 key* 또는 key1 이렇게 지정합니다.
  • key*는 key로 시작하는 모든 데이터(key,value)를 조회합니다.
  • 기본으로 Key로 정렬(sort)되어 있습니다.
  • 조건(예: string.key* or string.* where key glob 'key*')를 사용하면 인덱스를 사용해서 효율적이고 빠르게 처리합니다.
  • 다양한 조건(where)로 조회할 수 있습니다. GLOB(LIKE), BETWEEN, IN, 등
  • Group by, Order by, Limit 등을 사용할 수 있습니다.
  • SUM(), MIN(), MAX(), LEFT(), TRIM() 등 많은 함수를 사용할 수 있습니다.
  • Subquery를 사용할 수 있습니다.
  • UNION, INTERSECT, EXCEPT를 사용해서 복합 쿼리를 구성할 수 있습니다.

테스트 데이터 입력: Redis 명령으로 입력

도시 이름 데이터를 입력합니다.

Example

명령>rms (ls)     기존 데이터 삭제  
명령>mset mycity01 Seoul mycity02 Incheon mycity03 Chuncheon mycity04 Daejeon mycity05 Jeonju
결과>OK
명령>mset mycity06 Daegu mycity07 Gwangju mycity08 Busan mycity09 Jeju
결과>OK

SQL Insert 문으로 입력

Example

명령> insert into string values('mycity01','Seoul'), ('mycity02','Incheon'), ('mycity03','Chuncheon'),
('mycity04','Daejeon'), ('mycity05','Jeonju');
결과>5 inserted
명령> insert into string values('mycity06','Daegu'), ('mycity07','Gwangju'), ('mycity08','Busan'),
('mycity09','Jeju');
결과>4 inserted

동영상 설명은 아래에 있습니다.

String 데이터 조회

SELECT * FROM STRING.MYCITY*

String에서 mycity로 시작하는 키와 값(value)를 조회합니다.

Example

명령>select * from string.*;
결과> 0) key|value         키로 정렬되어 조회됩니다.
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity03|Chuncheon
4) mycity04|Daejeon
5) mycity05|Jeonju
6) mycity06|Daegu
7) mycity07|Gwangju
8) mycity08|Busan
9) mycity09|Jeju
명령>select * from string.mycity*;
결과> 0) key|value
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity03|Chuncheon
4) mycity04|Daejeon
5) mycity05|Jeonju
6) mycity06|Daegu
7) mycity07|Gwangju
8) mycity08|Busan
9) mycity09|Jeju
명령>select * from string.mycity05;
결과> 0) key|value
1) mycity05|Jeonju

WHERE

Where 조건으로 조회할 수 있습니다.
비교: =, <, <=, >, >=, !=, <>

Example

명령>select * from string.mycity* where value = 'Daejeon';
결과> 0) key|value
1) mycity04|Daejeon
명령>select * from string.mycity* where value <= 'Daejeon';
결과> 0) key|value
1) mycity03|Chuncheon
2) mycity04|Daejeon
3) mycity06|Daegu
4) mycity08|Busan
명령>select * from string.mycity* where value > 'Daejeon';
결과> 0) key|value
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity05|Jeonju
4) mycity07|Gwangju
5) mycity09|Jeju
명령>select * from string.mycity* where value != 'Daejeon';
결과> 0) key|value
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity03|Chuncheon
4) mycity05|Jeonju
5) mycity06|Daegu
6) mycity07|Gwangju
7) mycity08|Busan
8) mycity09|Jeju

BETWEEN

Example

명령>select * from string.mycity* where value BETWEEN 'Daejeon' and 'Jeju';
결과> 0) key|value
1) mycity02|Incheon
2) mycity04|Daejeon
3) mycity07|Gwangju
4) mycity09|Jeju
명령>select * from string.mycity* where value NOT BETWEEN 'Daejeon' and 'Jeju';
결과> 0) key|value
1) mycity01|Seoul
2) mycity03|Chuncheon
3) mycity05|Jeonju
4) mycity06|Daegu
5) mycity08|Busan

IN

Example

명령>select * from string.mycity* where key IN ('mycity03','mycity05') ;
결과> 0) key|value
1) mycity03|Chuncheon
2) mycity05|Jeonju
명령>select * from string.mycity* where key NOT IN ('mycity03','mycity05');
결과> 0) key|value
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity04|Daejeon
4) mycity06|Daegu
5) mycity07|Gwangju
6) mycity08|Busan
7) mycity09|Jeju

GLOB

Glob는 *(별표), ?(물음표)를 사용하고, 대소문자를 구분합니다.

Example

명령>select * from string.mycity* where value GLOB 'Dae*';
결과> 0) key|value
1) mycity04|Daejeon
2) mycity06|Daegu
명령>select * from string.mycity* where value GLOB 'Dae??';
결과> 0) key|value
1) mycity06|Daegu
명령>select * from string.mycity* where value GLOB '*ju';
결과> 0) key|value
1) mycity05|Jeonju
2) mycity07|Gwangju
3) mycity09|Jeju
명령>select * from string.mycity* where value NOT GLOB '*ju';
결과> 0) key|value
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity03|Chuncheon
4) mycity04|Daejeon
5) mycity06|Daegu
6) mycity08|Busan

LIKE

Like는 %(퍼센트), _(밑줄)을 사용하고, 대소문자를 구분하지 않습니다.

Example

명령>select * from string.mycity* where value LIKE 'dae%';
결과> 0) key|value
1) mycity04|Daejeon
2) mycity06|Daegu
명령>select * from string.mycity* where value LIKE '%ju';
결과> 0) key|value
1) mycity05|Jeonju
2) mycity07|Gwangju
3) mycity09|Jeju
명령>select * from string.mycity* where value NOT LIKE '%ju';
결과> 0) key|value
1) mycity01|Seoul
2) mycity02|Incheon
3) mycity03|Chuncheon
4) mycity04|Daejeon
5) mycity06|Daegu
6) mycity08|Busan

ORDER BY

Example

명령>select * from string.mycity* ORDER BY value;
결과> 0) key|value
1) mycity08|Busan
2) mycity03|Chuncheon
3) mycity06|Daegu
4) mycity04|Daejeon
5) mycity07|Gwangju
6) mycity02|Incheon
7) mycity09|Jeju
8) mycity05|Jeonju
9) mycity01|Seoul

LIMIT

출력 행수를 제한합니다.
  • LIMIT <숫자>: 숫자만큼 출력합니다.
  • LIMIT <숫자1, 숫자2>: 범위를 지정할 경우 사용합니다.
    숫자1은 시작 행수입니다. 0부터 시작합니다.
    숫자2는 제한 행수입니다.
    네 번째 행부터 네 행을 출력할 경우 3, 4를 지정합니다.

Example

명령>select * from string.mycity* order by value LIMIT 5;
결과> 0) key|value
1) mycity08|Busan
2) mycity03|Chuncheon
3) mycity06|Daegu
4) mycity04|Daejeon
5) mycity07|Gwangju
명령>select * from string.mycity* order by value LIMIT 3,4;
결과> 0) key|value
1) mycity04|Daejeon
2) mycity07|Gwangju
3) mycity02|Incheon
4) mycity09|Jeju

FUNCTIONS

COUNT(*)

Example

명령>select COUNT(*) from string.mycity*;
결과> 0) COUNT(*)
1) 9

MIN(), MAX()

Example

명령>select MIN(value),MAX(value) from string.mycity*;
결과> 0) min(value)|max(value)
1) Busan|Seoul

LENGTH()

Example

명령>select value name, LENGTH(value) length from string.mycity*;
결과> 0) name|length
1) Seoul|5
2) Incheon|7
3) Chuncheon|9
4) Daejeon|7
5) Jeonju|6
6) Daegu|5
7) Gwangju|7
8) Busan|5
9) Jeju|4

UPPER(), LOWER()

Example

명령>select UPPER(value), LOWER(value) from string.mycity*;
결과> 0) UPPER(value)|LOWER(value)
1) SEOUL|seoul
2) INCHEON|incheon
3) CHUNCHEON|chuncheon
4) DAEJEON|daejeon
5) JEONJU|jeonju
6) DAEGU|daegu
7) GWANGJU|gwangju
8) BUSAN|busan
9) JEJU|jeju

LEFT(), MID(), RIGHT()

Example

명령>select LEFT(value,2), MID(value,3,3), RIGHT(value,2) from string.mycity*;
결과> 0) LEFT(value,2)|MID(value,3,3)|RIGHT(value,2)
1) Se|oul|ul
2) In|che|on
3) Ch|unc|on
4) Da|eje|on
5) Je|onj|ju
6) Da|egu|gu
7) Gw|ang|ju
8) Bu|san|an
9) Je|ju|ju

기타 문자열 함수

  • REPLACE(): 문자열 바꾸기 REPLACE('ABC','B','D') -> ADC
  • INSTR(): 문자열이 포함된 첫 번째 순서 INSTR('ABC','B') -> 2
  • TRIM(): 양쪽 공백(space), 문자, 문자열 제거
  • LTRIM(): 왼쪽 공백(space), 문자, 문자열 제거
  • RTRIM(): 오른쪽 공백(space), 문자, 문자열 제거

숫자 함수

  • SUM(): 합계
  • AVG(): 평균
  • ROUND(): 반올림
  • ABS(): 절대값

도시 인구 테스트 데이터 입력

Example

명령>mset Seoul 9741383 Incheon 2925967 Chuncheon 283742 Daejeon 1525849 Jeonju 654963
결과>OK
명령>mset Daegu 2453041 Gwangju 1496172 Busan 3416918 Jeju 489202
결과>OK

SQL Insert로 입력

Example

명령> insert into string values('Seoul', 9741383), ('Incheon', 2925967), ('Chuncheon', 283742),
('Daejeon', 1525849), ('Jeonju', 654963);
결과>5 inserted
명령> insert into string values('Daegu', 2453041), ('Gwangju', 1496172), ('Busan', 3416918), ('Jeju', 489202);
결과>4 inserted

숫자(인구) 데이터 조회

조건 where key < 'a'; 는 mycity가 출력되지 않게 하려고 추가했습니다.

Example

명령>select * from string.* where key < 'a';
결과> 0) key|value
1) Busan|3416918
2) Chuncheon|283742
3) Daegu|2453041
4) Daejeon|1525849
5) Gwangju|1496172
6) Incheon|2925967
7) Jeju|489202
8) Jeonju|654963
9) Seoul|9741383
명령>select * from string.* where key < 'a' and value < 1000000;
결과> 0) key|value
1) Chuncheon|283742
2) Jeju|489202
3) Jeonju|654963
명령>select * from string.* where key < 'a' and value >= 1000000;
결과> 0) key|value
1) Busan|3416918
2) Daegu|2453041
3) Daejeon|1525849
4) Gwangju|1496172
5) Incheon|2925967
6) Seoul|9741383

SUM(), AVG()

Example

명령>select sum(value), avg(value) from string.* where key < 'a';
결과> 0) sum(value)|avg(value)
1) 22987237|2554137.44444444
명령>select min(value), max(value) from string.* where key < 'a';
결과> 0) min(value)|max(value)
1) 283742|9741383
명령>select key city, max(value) population from string.* where key < 'a';
결과> 0) city|population
1) Seoul|9741383

SET

테스트 데이터 입력: Redis 명령으로 입력

Example

명령>sadd myset1 Seoul Incheon Chuncheon Daejeon Jeonju
결과>5
명령>sadd myset2 Daejeon Jeonju Daegu Gwangju Busan Jeju
결과>6

SQL Insert로 입력

Example

명령> insert into set values('myset1', 'Seoul', 'Incheon', 'Chuncheon', 'Daejeon', 'Jeonju');
결과>1 inserted
명령> insert into set values('myset2', 'Daejeon', 'Jeonju', 'Daegu', 'Gwangju', 'Busan', 'Jeju');
결과>1 inserted

SET 데이터 조회

Set 데이터를 조회합니다.

Example

명령>select * from set.myset*;
결과>   0) key|value
  1) myset1|Seoul
  2) myset1|Daejeon
  3) myset1|Chuncheon
  4) myset1|Incheon
  5) myset1|Jeonju
  6) myset2|Daegu
  7) myset2|Jeonju
  8) myset2|Daejeon
  9) myset2|Gwangju
10) myset2|Busan
11) myset2|Jeju
명령>select * from set.myset1;
결과> 0) key|value
1) myset1|Seoul
2) myset1|Daejeon
3) myset1|Chuncheon
4) myset1|Incheon
5) myset1|Jeonju

GROUP BY

Example

명령>select key from set.myset*;
결과> 0) key
1) myset1
2) myset2
명령>select key, count(*) from set.myset* group by key;
결과> 0) key|count(*)
1) myset1|5
2) myset2|6
명령>select key, valcnt(key) from set.myset*;   group by에 비해서 속도 빠름
결과> 0) key|valcnt(key)
1) myset1|5
2) myset2|6

GROUP_CONCAT(*)

Example

명령>select key, group_concat(value) from set.myset* group by key ;
결과> 0) key|group_concat(value)
1) myset1|Seoul,Daejeon,Chuncheon,Incheon,Jeonju
2) myset2|Daegu,Jeonju,Daejeon,Gwangju,Busan,Jeju

WHERE

Example

명령>select * from set.myset1 where value = 'Seoul' ;
결과> 0) key|value
1) myset1|Seoul
명령>select * from set.myset1 where value glob '*cheon' ;
결과> 0) key|value
1) myset1|Chuncheon
2) myset1|Incheon

UNION, INTERSECT, EXCEPT

Example

명령>select value from set.myset1 union select value from set.myset2 ;
결과> 0) value
1) Busan
2) Chuncheon
3) Daegu
4) Daejeon
5) Gwangju
6) Incheon
7) Jeju
8) Jeonju
9) Seoul
명령>select value from set.myset1 intersect select value from set.myset2 ;
결과> 0) value
1) Daejeon
2) Jeonju
명령>select value from set.myset1 except select value from set.myset2 ;
결과> 0) value
1) Chuncheon
2) Incheon
3) Seoul

SUBQUERY

Example

명령>select * from string.* where key in (select value from set.myset1);
결과> 0) key|value
1) Chuncheon|283742
2) Daejeon|1525849
3) Incheon|2925967
4) Jeonju|654963
5) Seoul|9741383
명령>select sum(value),avg(value) from string.* where key in (select value from set.myset1);
결과> 0) sum(value)|avg(value)
1) 15131904|3026380.8

HASH

테스트 데이터 입력: Redis 명령으로 입력

Example

명령>rm Seoul Incheon Chuncheon Daejeon Jeonju Daegu Gwangju Busan Jeju   기존 데이터 삭제  
결과>9
명령>hset Seoul population 9741383 han 서울 area 605.20 mayor Kim
명령>hset Incheon population 2925967 han 인천 area 1062.60 mayor Lee
명령>hset Chuncheon population 283742 han 춘천 area 1116.35 mayor Cheo
명령>hset Daejeon population 1525849 han 대전 area 539.35 mayor Bak
명령>hset Jeonju population 654963 han 전주 area 206 mayor Son
명령>hset Daegu population 2453041 han 대구 area 883.57 mayor Jeong
명령>hset Gwangju population 1496172 han 광주 area 501.24 mayor Gang
명령>hset Busan population 3416918 han 부산 area 769.89 mayor Jo
명령>hset Jeju population 489202 han 제주 area 977.8 mayor Yun

SQL Insert 문으로 입력

Example

명령>delete from string.* where key < 'a';     기존 데이터 삭제  
결과>9 keys deleted
명령> insert into hash values('Seoul', 'population', 9741383, 'han', '서울', 'area', 605.20, 'mayor', 'Kim'),
    ('Incheon', 'population', 2925967, 'han', '인천', 'area', 1062.60, 'mayor', 'Lee'),
    ('Chuncheon', 'population', 283742, 'han', '춘천', 'area', 1116.35, 'mayor', 'Cheo'),
    ('Daejeon', 'population', 1525849, 'han', '대전', 'area', 539.35, 'mayor', 'Bak'),
    ('Jeonju', 'population', 654963, 'han', '전주', 'area', 206, 'mayor', 'Son'),
    ('Daegu', 'population', 2453041, 'han', '대구', 'area', 883.57, 'mayor', 'Jeong'),
    ('Gwangju', 'population', 1496172, 'han', '광주', 'area', 501.24, 'mayor', 'Gang'),
    ('Busan', 'population', 3416918, 'han', '부산', 'area', 769.89, 'mayor', 'Jo'),
    ('Jeju', 'population', 489202, 'han', '제주', 'area', 977.8, 'mayor', 'Yun');
명령>9 inserted

HASH 데이터 조회

Example

명령>select * from hash.*;
결과> 0) key|population|han|area|mayor
1) Busan|3416918|부산|769.89|Jo
2) Chuncheon|283742|춘천|1116.35|Cheo
3) Daegu|2453041|대구|883.57|Jeong
4) Daejeon|1525849|대전|539.35|Bak
5) Gwangju|1496172|광주|501.24|Gang
6) Incheon|2925967|인천|1062.6|Lee
7) Jeju|489202|제주|977.8|Yun
8) Jeonju|654963|전주|206|Son
9) Seoul|9741383|서울|605.2|Kim

Order by field

Example

명령>select * from hash.* order by han;
결과> 0) key|population|han|area|mayor
1) Gwangju|1496172|광주|501.24|Gang
2) Daegu|2453041|대구|883.57|Jeong
3) Daejeon|1525849|대전|539.35|Bak
4) Busan|3416918|부산|769.89|Jo
5) Seoul|9741383|서울|605.2|Kim
6) Incheon|2925967|인천|1062.6|Lee
7) Jeonju|654963|전주|206|Son
8) Jeju|489202|제주|977.8|Yun
9) Chuncheon|283742|춘천|1116.35|Cheo

Where field

Example

명령>select * from hash.* where population > 1000000;
결과> 0) key|population|han|area|mayor
1) Busan|3416918|부산|769.89|Jo
2) Daegu|2453041|대구|883.57|Jeong
3) Daejeon|1525849|대전|539.35|Bak
4) Gwangju|1496172|광주|501.24|Gang
5) Incheon|2925967|인천|1062.6|Lee
6) Seoul|9741383|서울|605.2|Kim

계산

Example

명령>select key,han,round(population/area,1) from hash.*;
결과> 0) key|han|round(population/area,1)
1) Busan|부산|4438.2
2) Chuncheon|춘천|254.2
3) Daegu|대구|2776.3
4) Daejeon|대전|2829.1
5) Gwangju|광주|2984.9
6) Incheon|인천|2753.6
7) Jeju|제주|500.3
8) Jeonju|전주|3179.0
9) Seoul|서울|16096.1
명령>select key,han,round(population/area,1) density from hash.* order by density desc;
결과> 0) key|han|density
1) Seoul|서울|16096.1
2) Busan|부산|4438.2
3) Jeonju|전주|3179.0
4) Gwangju|광주|2984.9
5) Daejeon|대전|2829.1
6) Daegu|대구|2776.3
7) Incheon|인천|2753.6
8) Jeju|제주|500.3
9) Chuncheon|춘천|254.2

SUBQUERY

Example

명령>select * from hash.* where key in (select value from set.myset1);
결과> 0) key|population|han|area|mayor
1) Chuncheon|283742|춘천|1116.35|Cheo
2) Daejeon|1525849|대전|539.35|Bak
3) Incheon|2925967|인천|1062.6|Lee
4) Jeonju|654963|전주|206|Son
5) Seoul|9741383|서울|605.2|Kim

동영상 설명

Redis SQL Select Introduction 1

Redis SQL Select Introduction 2

Redis SQL Select Introduction 3


Performance 성능

Redis-benchmark 성능

Datatype명령Cmds per sec SQL SELECT
(Cmds per sec)
비교
STRINGGET115,76747,851 41%
LISTLRANGE 63,53616,382 26%
SETSMEMBERS 69,15616,423 24%
ZSETZRANGE 17,02110,001 59%
HASHHGETALL 25,4714,264 17%
합계 29095194921 33%
  • Redis-benchmark로 redis 원래 명령과 select를 각각 10만회 조회, 실행 시간 비교
  • String은 value 1개, List 부터 Hash까지는 value 100개를 조회한 것이다.
  • Redis 원래 명령에 비해 select가 평균 33% 성능이 나온다.

STRING

  • GET: src/redis-benchmark -p 7000 -c 10 -n 100000 -r 1000000 get keyA___rand_int__
    100000 requests completed in 8.64 seconds, 115767.55 requests per second
  • SELECT: src/redis-benchmark -p 7000 -c 10 -n 100000 -r 1000000 --hello --ignoreerr select "select * from string.keyA___rand_int__;"
    100000 requests completed in 20.90 seconds, 47851.47 requests per second

LIST

  • Test Data Input: src/redis-benchmark -p 7000 -c 1 -n 100 -r 100 insert "insert into list values ('mylist1','value___rand_int__')"
  • LRANGE: src/redis-benchmark -p 7000 -c 10 -n 100000 lrange mylist1 0 -1 100000 requests completed in 15.74 seconds, 63536.44 requests per second
  • SELECT: src/redis-benchmark -p 7000 -c 10 -n 100000 --hello --ignoreerr select "select * from list.mylist1;" 100000 requests completed in 6.10 seconds, 16382.70 requests per second

SET

  • Test Data Input: src/redis-benchmark -p 7000 -c 1 -n 100 -r 10000 insert "insert into set values ('myset1','value___rand_int__')"
  • SMEMBERS: src/redis-benchmark -p 7000 -c 10 -n 100000 smembers myset1 100000 requests completed in 1.45 seconds, 69156.30 requests per second
  • SELECT: src/redis-benchmark -p 7000 -c 10 -n 100000 --hello --ignoreerr select "select * from set.myset1;" 100000 requests completed in 6.09 seconds, 16423.06 requests per second

ZSET

  • Test Data Input: src/redis-benchmark -p 7000 -c 1 -n 100 -r 10000 insert "insert into zset values ('zset1',__rand_int__,'value___rand_int__')"
  • ZRANGE: src/redis-benchmark -p 7000 -c 10 -n 100000 zrange zset1 0 -1 withscores 100000 requests completed in 5.88 seconds, 17021.28 requests per second
  • SELECT: src/redis-benchmark -p 7000 -c 10 -n 100000 --hello --ignoreerr select "select * from zset.zset1;" 100000 requests completed in 10.00 seconds, 10001.00 requests per second

HASH

  • Test Data Input: src/redis-benchmark -p 7000 -c 1 -n 100 -r 10000 insert "insert into hash values ('myhash1', 'field___rand_int__', 'value___rand_int__')"
  • HGETALL: src/redis-benchmark -p 7000 -c 10 -n 100000 hgetall myhash1 100000 requests completed in 3.93 seconds, 25471.22 requests per second
  • SELECT: src/redis-benchmark -p 7000 -c 10 -n 100000 --hello --ignoreerr select "select * from hash.myhash1;" 100000 requests completed in 23.45 seconds, 4264.21 requests per second

<< Commands Select Intro Select String >>

Email 返事がかかってなれば、メールでお知らせします。