NoSQL初心者のためのDynamoDBデータ構造
ご無沙汰しております!
最近たくさんの方に入社いただき、ついに平均年齢を上回ってしまったこまっちゃんです。
さて、今回はDynamoDBのデータ構造について解説したいと思います。
かくいう私はRDB設計ばかり行なっているので、DynamoDBは初心者です
あくまで現時点の情報となりますので、最新のソースのご確認をお願いいたします!
記事の対象となる方
- RDBMS(SQL)の設計に慣れている方
- NoSQLの設計をしたことがない/これから挑戦したいと思っている方
DynamoDBの特徴
そもそも、DynamoDBはどんな特徴があるの?というところですが、以下の様なメリットを持っています。
- フルマネージドでサーバーレスなので、レプリケーションやスケーリングが自動で実行される
- jsonのようなkey-value形式でデータを取得するNoSQLデータベース
- インメモリキャッシュを保持した、低レイテンシーな読み取り
- 自動的にスケーリングすることによる高い書き込みパフォーマンス
一方、もちろんデメリットも存在します。
- NoSQLのため、デーブルをjoinするような複雑な検索や集計処理は難しい
- 可用性を維持するために、データの一貫性が損なわれることがある※
(自動的にデータをバックアップ(レプリケーション)するので、データ更新・取得がほぼ同時に起こった場合に、更新前のデータを返してしまうことがある)
以上を踏まえると、DynamoDBのユースケースとしては以下のようなものがおすすめです。
複雑な検索条件があったり、テーブル同士を結合する必要があったり、集計が必要なワークロードがある場合はRDBMSの検討をすると良さそうですね。
- ゲームなどの水平スケールが必要なシステム
- 複雑なSQL検索条件を使用しないが、低レイテンシーが必要なシステム
- 運用コストを下げたいケース
DynamoDBのデータ構造
部員ひとりひとりにIDが割り振られる、以下のような部員テーブルがあったとします。
パーティションキー | ソートキー | ||
ID | 役職 | 名前 | 学年 |
---|---|---|---|
1 | 部長 | 鈴木春人 | 3 |
2 | 副部長 | 武内夏美 | 2 |
3 | 部員 | 高橋秋 | 1 |
4 | 部員 | 横山冬樹 | 2 |
DynamoDBはkey-value形式であると前述しましたが、item(レコード)を取得するためのキー(プライマリキー)は2種類しか指定できません。
独立したパーティションキーのみで検索するか、パーティションキー + ソートキーの複合ユニークキーで検索するか、です。
上の表のように、IDが独立していればパーティションキーのみでitemを取得できますね。
一方、もし「役職」がパーティションキーだった場合、「部員」が重複しているので新しくソートキー(IDや名前)を指定して、キーがユニークになるようにしてあげる必要があります。
絞り込みに使用するキーを適切に指定しないと、検索範囲が広がってしまいせっかくの低レイテンシーが維持できなくなってしまうので注意しましょう。
ただし、「役職」をパーティションキーに指定するメリットもあります。例えば「部員」だけを設定した場合、DynamoDBは「部員」全員を取得することができます。
パーティションキー
ここで、パーティションキーを深掘りしてみます。DynamoDB は、itemを保存する箱(パーティション)に入れるためにパーティションキーをハッシュ化して使います。そのため、パーティションキーは必須です!複数のitemが同じパーティションキーを持っている場合、ソートキーでソートされ、まとめて箱に保存されます。
パーティションキーを設計する際は、パーティションキーへのアクセスが分散することが重要です。あるパーティションキーにアクセスが集中してしまうと、スロットリングしたり、データベースの容量を適切に使用できなくなることがあるためです(=「ホット」パーティション)。
例えば、社員が1万人いる会社があるとします。
- 社員IDをパーティションキーにする
- 出勤/欠勤のステータスをパーティションキーにする
①の場合、アクセスは分散しそうですが、②の場合「出勤」に極端にアクセスが集中してしまいそうですよね。データにどんな、どれだけのアクセスが想定されるかを考慮して設計していきましょう。
ソートキー
前述した通り、パーティションキーが同じ場合、itemはソートキーで昇順にソートされてパーティションに保存されます。ソートキーは必須ではありませんが、範囲クエリを指定することでグループ検索をすることができたり、降順にデータを取得することも可能です。
<>, == といった演算子を使用してクエリを発行できるので、RDBMSに慣れ親しんだ人にも使いやすいキーかもしれませんね。
その他の検索方法
では、「パーティションキーやソートキー以外で絞り込みを行いたい」
「ソート条件を複数指定したい」という場合、どのように設計すれば良いでしょう。
ここで活躍するのが、セカンダリインデックスです。
DynamoDBは2種類のセカンダリインデックスをサポートしています。
Local Secondary Index (LSI)
LSIには以下のような特徴があります。
- ソートキー以外に絞り込み検索を行うkeyを持つことができる
- パーティションキーが同一で、ソートキー以外(Attributes)を使用する検索に利用できる
例えば以下の例の場合、DWSが何年に何の曲を発表したのかは検索することができません。
パーティションキー | ソートキー | |
アーティスト名 | 曲名 | 発表年 |
---|---|---|
DWS | more professional | 2010 |
DWS | more trust | 2010 |
DWS | more fun | 2009 |
しかし、「発表年」をLSIに指定することで、発表年別に絞り込みができるようになります。
パーティションキー | ソートキー | |
アーティスト名 | 発表年 | 曲名 |
---|---|---|
DWS | 2009 | more fun |
DWS | 2010 | more professional |
DWS | 2010 | more trust |
DynamoDB の各テーブルには5つのLSIを設定することが可能です。LSIは以下の点が注意点として挙げられるため、一般的には次のGSIを使用することが推奨されています。
- 複数のパーティションにまたがった検索はできない(GSIで行う)
- テーブル作成後に追加できない(GSIは可能)
しかし、結果整合性・強い結果整合性の両方をサポートしているので、強い整合性モデルを採用する場合はLSIを使うと良いです(GSIは結果整合性のみサポート)。強い結果生合成を有効にしたい場合は、クエリでConsistentReadをtrueに指定します。
Global Secondary Index (GSI)
複数のパーティションにまたがった検索が可能なため「グローバル」と名前がついています。GSIは各テーブルに20個まで設定可能です。
先ほどの例では発表年から検索を行うことができないので、GSIを使用してパーティションキーを交換することで、行いたかった検索が実現できます。
パーティションキー | ソートキー | |
発表年 | アーティスト名 | 曲名 |
---|---|---|
2009 | DWS | more fun |
2010 | DWS | more professional |
2010 | DWS | more trust |
LSI/GSIの細かな違いについては、ぜひ公式サイトからご確認ください。
このように非常に便利なセカンダリインデックスですが、デメリットも存在します。インデックスはストレージやプロビジョニング済みのスループットを消費するため、設定すればするほどパフォーマンスに悪影響を及ぼしてしまいます。
セカンダリインデックスを使用する際は、インデックス数は最小限に抑えましょう。頻繁にクエリを行わない属性では、極力セカンダリインデックスを作成しないようにすると良いですね。
まとめ
いかがでしたでしょうか。
DynamoDBはキーの設計が全てと言っても過言ではありません。
key-valueというシンプルな形式であるがゆえに低レイテンシーで高いスループットを誇るDynamoDBですが、SQLのような複雑なクエリや集計等は苦手です。極力シンプルな構成にし、想定されるユースケースを元に適切なキーを設定しましょう。
複雑な検索が必要なケースが多い場合は、そもそもDynamoDBを選択せず、RDSMSからデータベースを選択するのも大事な手です。
NoSQL初心者の皆さんに少しでもお役に立てたなら幸いです。