主ストア
読み取りを、参照のまま保つ
「この顧客の、まだ open な注文をすべて」。「このカートに何点入っているか」。これらはアプリケーションが毎秒何千回も行う読み取りであり、リレーショナルデータベースでは、そのひとつひとつが、裏にプランナを抱えたクエリになります。kevy なら、答えを用意しておけます。
なぜ向いているのか
キーバリューストアをアプリケーションのデータに使うことは、たいていひとつの反論で退けられます。キー以外のもので引きたいのだが、と。その反論は正しく、セカンダリインデックスは、まさにそのためにあります。
インデックスは、構築するものではなく宣言するものです。キーのパターンとフィールドを指定すれば、書き込みの側が、それを最新に保ちます。絞り込んだ一覧は、ふたたび参照になります。プランナもスキャンもクエリもありません。
ビューはさらに進んで、書き込み時に集計を最新に保ちます。件数や合計は、計算されるのではなく読まれます。ほとんどのアプリケーションが ORM に実際に求めているのはこれであり、データベースが忙しい理由も、これです。
手順
# your data, written the way you would anyway
HSET order:1001 customer 881 status open total 4400
HSET order:1002 customer 881 status paid total 8400
HSET order:1003 customer 902 status open total 1200
# one index per field you want to look up by
IDX.CREATE idx:cust ON PREFIX order: FIELD customer TYPE i64 KIND range
IDX.CREATE idx:status ON PREFIX order: FIELD status TYPE str KIND range
# the read that would have been a query
IDX.QUERY idx:cust EQ 881
-> 1) "0" # cursor
2) 1) "order:1001" 2) "881"
3) "order:1002" 4) "881"
# two conditions at once
IDX.QUERY COMPOSE AND idx:cust EQ 881 idx:status EQ open
-> 1) "0"
2) 1) 1) "order:1001"
# a VIEW keeps the answer ready on the WRITE path, so the read
# never recomputes it. (the parens are separate arguments.)
VIEW.CREATE v:open881 QUERY ( AND idx:cust EQ 881 idx:status EQ open ) ORDER BY idx:cust
VIEW.QUERY v:open881
-> 1) "0"
2) 1) "order:1001" 2) "881"
何を差し出すことになるか
インデックスとビューの代金は、読み取りではなく、書き込みのたびに支払います。それが取引の条件であり、読み取り主体の配信には正しく、書き込み主体のログには間違っています。結合はありませんし、今後も持ちません。インデックスが答えるのは「どのキーがこれらのフィールドに合致するか」であって、「この 2 つのコレクションを結合せよ」ではありません。読み取りに本当に結合が要るなら、Postgres に置いておいてください。リレーショナルな各ワークロードが、ここでいくらかかるかを書いてあります。答えが「移さないほうがいい」になるものも含めて。