Dynamo で少し複雑なデータを取りたいので GSI を貼ってみた
グローバルセカンダリインデックス(GSI)とは
Dynamo DB では scan という総当り検索と、
query というインデックスを貼っている値を検索する機能しかデータ抽出機能がありません。
つまり、O(log n)のパフォーマンスでデータを取得したい場合はキーになっている値しか高速に検索ができないのです。
実はローカルセカンダリーインデックス(LSI)というのもいるのですが、こいつは DB 作成時にしか設定できないそうなので後付で対応できる GSI についてのみ解説しようと思います。
GSI で何ができるの?
キーになっていない 項目(Attributes)にもインデックスを貼ることができます。
つまり、query を発行して高速でデータ取得できる仕組みを後付できます。
とある Attributes を条件に入れる必要が出てきた場合に大きな力になってくれます。
GSI の制約
GSI ですが、基本的には 1Table につき 5 個までしか設定できないそうです。
また、インデックスを増やすと書き込みによるインデックス作成のコストが増えるそうなので頻繁に filter する必要がある場合を除いて設定しないほうが良いのかもしれません。
ただ、難しく考えすぎず、結構使いそうなら GSI を作成してしまえばいいと思います。
※ローカルセカンダリーインデックスの場合でも同様にコストは増えます。
余談ですが、以下に RDB との雰囲気対応表をおいておきます。
雰囲気対応表
DynamoDB | RDBMS |
---|---|
Table | Table |
Item | Row |
Attributes | Column |
Partition Key | Primary Key |
Sort Key | 指定する場合は Primary Key を構成する一部になる |
ユースケース
仕様を書いただけではイメージし辛いのでユースケースを考えてみたいと思います。
「1 万~ 3 万の商品を購入したことのあるユーザーを任意の期間で知りたい」
ユーザー ID | ユーザー | 価格 | 購入日 | 購入 No. | 商品 ID | 商品名 | 個数 | 店舗 | 従業員 | 合計金額 |
---|---|---|---|---|---|---|---|---|---|---|
user_id | user_name | price | purchase_date | purchase_no | product_id | product_name | amount | store_id | employee_id | total_price |
C1 | コウペンちゃん | 19800 | 2022/09/05 | 1 | 001 | おしゃべりコウペンちゃん | 1 | A1 | 001 | 19800 |
C2 | ピンクコウペンちゃん | 19800 | 2022/09/05 | 2 | 001 | おしゃべりコウペンちゃん | 1 | A1 | 001 | 19800 |
イメージとしてはこんな感じのテーブルです。
既存のユースケースでは購入日ごとの合計売上を知りたいことが多いので
購入日がパティションキーで、購入 No.がソートキーに設定されています。
今回は GSI として、パーティションキーはそのまま購入日で価格をソートキーにとして設定します。
本来なら scan でしか抽出できなかったのですが、この用に GSI を設定することで
「1 万~ 3 万の商品を購入したことのあるユーザーを任意の期間で知りたい」というユースケースを満たすことができます。
Discussion