본문 바로가기

빅데이터/cassandra

카산드라 모델링 분석하기 좋은 테이블 구성하기

기본적으로 생각해야할 부분은 컬럼 기반 데이터베이스라는 점입니다. 이를 기억하고 수행해야 합니다.

 

1개 필드를 프라이머리 키(파티션 키)로 생성한 테이블

cqlsh:cory> create table log1(uid int, machine varchar, log_time timestamp, log varchar, primary key(uid));

 

- uid : int

- machine : varchar

- log_time : timestmp

- log : varchar

primary key이자 partition key는 uid로 설정

 

1) 데이터 insert

cqlsh:cory> insert into log1(uid, log, log_time, machine) values(1,'gg',toTimestamp(now()),'1');
cqlsh:cory> insert into log1(uid, log, log_time, machine) values(2,'gg',toTimestamp(now()),'2');
cqlsh:cory> insert into log1(uid, log, log_time, machine) values(3,'gg',toTimestamp(now()),'3');
cqlsh:cory> insert into log1(uid, log, log_time, machine) values(4,'gg',toTimestamp(now()),'4');

2) 모든 데이터 조회

cqlsh:cory> select * from cory.log1;

 uid | log | log_time                        | machine
-----+-----+---------------------------------+---------
   1 |  gg | 2021-11-11 01:20:54.335000+0000 |       1
   2 |  gg | 2021-11-11 01:21:02.705000+0000 |       2
   4 |  gg | 2021-11-11 01:21:13.692000+0000 |       4
   3 |  gg | 2021-11-11 01:21:08.301000+0000 |       3

3) uid 기반 데이터 조회

cqlsh:cory> select * from cory.log1 where uid=1;

 uid | log | log_time                        | machine
-----+-----+---------------------------------+---------
   1 |  gg | 2021-11-11 01:20:54.335000+0000 |       1

정상적으로 수행되는 것을 알 수 있습니다.

 

4) machine 또는 log_time 기반 데이터 조회

cqlsh:cory> select * from cory.log1 where machine='1';
InvalidRequest: Error from server: code=2200 [Invalid query] 
message="Cannot execute this query as it might involve data filtering 
and thus may have unpredictable performance. If you want to execute this query 
despite the performance unpredictability, use ALLOW FILTERING"
cqlsh:cory> select * from cory.log1 where log_time > '2013-04-03 00:00:00' ;
InvalidRequest: Error from server: code=2200 [Invalid query] 
message="Cannot execute this query as it might involve data filtering 
and thus may have unpredictable performance. If you want to execute this query 
despite the performance unpredictability, use ALLOW FILTERING"

machine과 log_time이 파티션 키가 아니기 때문에 필터링 조건을 만족시키지 못하고 데이터를 리턴하지 않는 모습.

 

5) uid order by 수행하기

cqlsh:cory> select * from log1 where uid=1 order by uid;
InvalidRequest: Error from server: code=2200 [Invalid query] message="Order by is currently only supported 
on the clustered columns of the PRIMARY KEY, got uid"

order by 를 수행하기 위해서는 테이블을 생성할 때 clustering key를 사용하여 order by 조건을 미리 선언해야 합니다.

Example)
CREATE TABLE playlists ( 
    id uuid, song_order int, song_id uuid, title text, album text, artist text, 
    PRIMARY KEY (id, song_order)) WITH CLUSTERING ORDER BY (song_order ASC);

https://stackoverflow.com/a/23808224/9634545

 

Order by is currently only supported on the clustered columns of the PRIMARY KEY

cassandra2.0.7 cql 3.1.1 CREATE TABLE playlists ( id uuid, song_order int, song_id uuid, title text, album text, artist text, PRIMARY KEY (id, song_order ) ); INSERT INTO playlis...

stackoverflow.com

6) uid가 중복되는 데이터 insert하기

cqlsh:cory> insert into log1(uid, log, log_time, machine) values(4,'gg',toTimestamp(now()),'4');
cqlsh:cory> select * from log1;

 uid | log | log_time                        | machine
-----+-----+---------------------------------+---------
   1 |  gg | 2021-11-11 01:20:54.335000+0000 |       1
   2 |  gg | 2021-11-11 01:21:02.705000+0000 |       2
   4 |  gg | 2021-11-11 01:29:39.111000+0000 |       4
   3 |  gg | 2021-11-11 01:21:08.301000+0000 |       3

동일 파티션키로 insert할 경우 update로 수행합니다.

cqlsh:cory> update log1 set log='newnew' where uid=4;
cqlsh:cory> select * from log1;

 uid | log    | log_time                        | machine
-----+--------+---------------------------------+---------
   1 |     gg | 2021-11-11 01:20:54.335000+0000 |       1
   2 |     gg | 2021-11-11 01:21:02.705000+0000 |       2
   4 | newnew | 2021-11-11 01:30:26.355000+0000 |       4
   3 |     gg | 2021-11-11 01:21:08.301000+0000 |       3
cqlsh:cory> insert into log1(uid, log, machine) values(4,'gg','5');
cqlsh:cory> select * from log1;

 uid | log | log_time                        | machine
-----+-----+---------------------------------+---------
   1 |  gg | 2021-11-11 01:20:54.335000+0000 |       1
   2 |  gg | 2021-11-11 01:21:02.705000+0000 |       2
   4 |  gg | 2021-11-11 01:30:26.355000+0000 |       5
   3 |  gg | 2021-11-11 01:21:08.301000+0000 |       3

update와 insert의 동작이 파티션 키 기준으로 동일하게 수행되는 것을 알 수 있습니다.

 

set 데이터 타입이 포함된 테이블

set 데이터 타입이 추가되어 있는 테이블

cqlsh:cory> create table log2(uid int, log text, user set<text>, primary key (uid));
cqlsh:cory> insert into log2(uid,log,user)values(1,'a',{'1'});
cqlsh:cory> select * from log2;

 uid | user   | log
-----+-------+-----
   1 | {'1'} |   a
cqlsh:cory> update log2 set user = user + {'2'} where uid = 1;
cqlsh:cory> select * from log2;

 uid | user        | log
-----+------------+-----
   1 | {'1', '2'} |   a

update를 통해 기존 set 데이터 타입에 데이터를 추가. 다만, 이 경우에 반드시 파티션 키(uid)를 지정해야만 합니다.

 

복합 primary key를 활용한 테이블

cqlsh:cory> create table log3(machine_id varchar, log_time timestamp, log_text varchar, primary key(machine_id, log_time));
cqlsh:cory> insert into log3(machine_id, log_time, log_text) values('a',toTimestamp(now()),'a');
cqlsh:cory> select * from log3;

 machine_id | log_time                        | log_text
------------+---------------------------------+----------
          a | 2021-11-11 03:20:48.279000+0000 |        a

(1 rows)

- machine_id : varchar

- log_time : timestamp

- log_text : varchar

primary key : machine_id, log_time 함께 사용

-> machine_id로 == 또는 IN 쿼리가능
-> log_time(컬럼 키)로 Range query 가능

cqlsh:cory> insert into log3(machine_id, log_time, log_text) values('a',toTimestamp(now()),'a');
cqlsh:cory> select * from log3;

 machine_id | log_time                        | log_text
------------+---------------------------------+----------
          a | 2021-11-11 03:20:48.279000+0000 |        a
          a | 2021-11-11 03:21:04.350000+0000 |        a

(2 rows)
cqlsh:cory> insert into log3(machine_id, log_time, log_text) values('a',toTimestamp(now()),'a');
cqlsh:cory> select * from log3;

 machine_id | log_time                        | log_text
------------+---------------------------------+----------
          a | 2021-11-11 03:20:48.279000+0000 |        a
          a | 2021-11-11 03:21:04.350000+0000 |        a
          a | 2021-11-11 03:21:22.253000+0000 |        a

(3 rows)
cqlsh:cory> select * from log3 where machine_id='a' and log_time > '2021-11-11 03:21:04';

 machine_id | log_time                        | log_text
------------+---------------------------------+----------
          a | 2021-11-11 03:21:04.350000+0000 |        a
          a | 2021-11-11 03:21:22.253000+0000 |        a

(2 rows)

range 쿼리 수행 완료되었습니다.

cqlsh:cory> select * from log3 where machine_id='a' and log_time > '2021-11-11 03:21:04' order by log_time;

 machine_id | log_time                        | log_text
------------+---------------------------------+----------
          a | 2021-11-11 03:21:04.350000+0000 |        a
          a | 2021-11-11 03:21:22.253000+0000 |        a

(2 rows)

시간당 정렬도 가능합니다.

 

그러나, 하나의 row에 계속해서 column데이터가 추가되기 때문에 Ultra Wide Row로 수행됨. 이는 적절치 않음. 관련 모델링 내용은 아래 포스팅에서 확인할 수 있습니다.

https://blog.voidmainvoid.net/240

 

NoSQL강의) 모델링 예제로 알아보는 Cassandra Query Language (CQL)

모델링 example 1 - Log 데이터 저장요구조건 - machine_id , log_time, log_text - machine 100EA, 1초당 로그 1건씩, 로그는 일반 텍스트 Case 1 : 별도의 PK를 부여한다면? CREATE TABLE log1 ( uid int, mac..

blog.voidmainvoid.net

가장 좋은 테이블 생성 예제.

machine_id, log_date를 row key, log_time을 column key로 사용합니다.

machine_id, log_date 2개를 조합하여 파티션 키를 만든것이 composite key라고 부릅니다.

cqlsh:cory>  CREATE TABLE log4 (
        ...   machine_id varchar,
        ...   log_date varchar,
        ...   log_time timestamp,
        ...   log_text varchar,
        ...   PRIMARY KEY ((machine_id,log_date),log_time)
        ... );
cqlsh:cory> insert into log4(machine_id, log_date,log_time, log_text) values('a','20211111',toTimestamp(now()),'a');
cqlsh:cory> select * from log4;

 machine_id | log_date | log_time                        | log_text
------------+----------+---------------------------------+----------
          a | 20211111 | 2021-11-11 03:27:40.635000+0000 |        a

(1 rows)
cqlsh:cory> insert into log4(machine_id, log_date,log_time, log_text) values('a','20211111',toTimestamp(now()),'a');
cqlsh:cory> select * from log4;

 machine_id | log_date | log_time                        | log_text
------------+----------+---------------------------------+----------
          a | 20211111 | 2021-11-11 03:27:40.635000+0000 |        a
          a | 20211111 | 2021-11-11 03:28:05.926000+0000 |        a

(2 rows)

이 경우 machine_id와 log_date 기준으로 쿼리를 수행하고 범위 지정 및 오더링은 log_time으로 수행.

가장 좋은 테이블 구성이라고 볼 수 있습니다.

 

결론

 

반응형