Cassandraへのクエリの注意点
Cassandraでテーブルを設計する際、どのようなクエリが実行されるのか想定する必要がある。というのも、Cassandraではテーブルへのクエリに多くの制約があるため、これを知らずにテーブルを設計すると期待していたクエリが実行できない事態になってしまう。
そこで、クエリにどのような制約があるかまとめることにした。例に使うテーブルは以下のようなスキーマで作成した。
create table access_logs (
date int,
time timestamp,
path text,
method text,
user_id bigint,
primary key ((date), time, path, method)
) with clustering order by (time desc, path asc, method asc);
他にもあるかもしれないし、バージョンによって変わりうるが、v3.11.10で検証したところ以下のような制約が見つかった。
- パーティションキーは必須
- クラスタリングキーは前方のカラムを省略できない
- プライマリーキーに含まれていないカラムを指定できない
- ORは使えない
- NOTは使えない
- 不等号は最後に指定するカラムにしか使えない
- OFFSETは使えない
パーティションキーは必須
--- NG
select
*
from
access_logs
where
time = '2021-01-01 00:00:00'
;
--- OK
select
*
from
access_logs
where
date = 20210101
and time = '2021-01-01 00:00:00'
;
データを返すノードを決定するためにパーティションキーをすべて指定する必要がある。
クラスタリングキーは前方のカラムを省略できない
--- NG
select
*
from
access_logs
where
date = 20210101
and path = '/'
;
--- OK
select
*
from
access_logs
where
date = 20210101
and time = '2021-01-01 00:00:00'
and path = '/'
;
あるクラスタリングキーよりも前に定義されているクラスタリングキーがあれば、それも指定する必要がある。
プライマリーキーに含まれていないカラムを指定できない
--- NG
select
*
from
access_logs
where
date = 20210101
and time = '2021-01-01 00:00:00'
and path = '/'
and method = 'GET'
and user_id = 1
;
--- OK
select
*
from
access_logs
where
date = 20210101
and time = '2021-01-01 00:00:00'
and path = '/'
and method = 'GET'
;
ORは使えない
--- NG
select
*
from
access_logs
where
date = 20210101
and (time = '2021-01-01 00:00:00' or time = '2021-01-02 00:00:00')
;
--- OK
select
*
from
access_logs
where
date = 20210101
and time in ('2021-01-01 00:00:00', '2021-01-02 00:00:00')
;
NOTは使えない
--- NG
select
*
from
access_logs
where
date = 20210101
and time <> '2021-01-01 00:00:00'
;
--- OK
select
*
from
access_logs
where
date = 20210101
and time > '2021-01-01 00:00:00'
;
Cassandraがシーケンシャルリードのために設計されており、ランダムリードを生じさせるOR
やNOT
はサポートされていない。
不等号は最後に指定するカラムにしか使えない
--- NG
select
*
from
access_logs
where
date = 20210101
and time >= '2021-01-01 00:00:00'
and path = '/'
;
--- OK
select
*
from
access_logs
where
date = 20210101
and time >= '2021-01-01 00:00:00'
;
OFFSETは使えない
--- NG
select
*
from
access_logs
where
date = 20210101
limit
1
offset
1
;
--- OK
select
*
from
access_logs
where
date = 20210101
limit
1
;
LIMIT
は使えるもののOFFSET
が使えないため、SQLのようにページネーションを実装できない。ページネーションの実装については以前の記事に書いた。
ALLOW FILTERING
これらの制約はエラーメッセージにもあるとおりALLOW FILTERING
で回避することができるが、パフォーマンスに重大な影響をあたえる可能性があるため推奨されていない。詳細については以前の記事にも書いている。