AWS DynamoDB NoSQL設計
RDBMS と NoSQL
RDBMS 設計
正規化されたデータモデルを考え、要件にあわせてデータモデルを拡張することができる
NoSQL 設計
アクセスパターンを考慮した設計が必要 となる
つまり、アプリケーションのユースケースの理解、分析が非常に重要となる
設計が優れていれば、必要なテーブルは 1 つに止まるはずである
NoSQL の設計
前述の通り、システムのクエリのパターンを分析することが重要となる。このアクセスパターンの特性として基本的なものは、以下の 3 つ。
データサイズ
一度に格納/リクエストされるデータ量
データ分割方法を決めるのに役立つ
データシェイプ
クエリ処理時にデータを形成するのではなく、DB 内の形状がクエリされるものと一致させる
スピード、スケーラビリティを向上させる
データ速度
ピーク時のクエリの負荷を事前に把握する
効率的にデータを分散させる必要がある
データ分割方法の決定に役立つ
パフォーマンスを管理する一般的な原則は以下。これらに従って、データを整理する
関連するデータをまとめる
参照の局所性
大容量時亀裂データ、データセットのアクセスパターンが非常に異なる場合等は例外
クエリを分散する
DB の一部にクエリを集中させない
いわゆるホットスポットになることを避ける
グローバルセカンダリインデックスを使用する
メインテーブルでサポートできるクエリとはこtなるクエリを有効にできる
R/W 分散のための Tips
データの書き込み、読み込みを均一に分散するためのプラクティスがいくつか紹介されている。
書き込み効率化のための Tips
ソートキーを利用した書き込み
データを一度に大量にアップロードする場合、1つのパーティションに一気に書き込むよりも、複数のパーティションに一気に格納した方が良いのは自明である。
UserID をパーティションキー、Message ID をソートキーとする。以下の順でデータを挿入したとする。
table:table
USerId MessageId
1 1
1 2
1 ...
1 100
2 1
2 2
2 ...
2 300
パーティションキー 1 のパーティション、2 のパーティションにシーケンシャルに書き込みを行なっており、また、パーティションごとにその書き込み量もバラバラで、分散できていない。こういう場合は、ソートキーを使ってソートしてから書き込みを行う。
table:table
USerId MessageId
1 1
2 1
3 1
... ...
1 2
2 2
3 2
... ...
これにより、書き込み先のパーティションを分散できる。
書き込みシャーディングを利用した分散方法
ランダムなサフィックスを使用したシャーディング
例えば、日毎に大量の書き込みがあり、それらを均一に分散したい、とする。
この場合、 <日付>-<一定範囲の乱数> をパーティションキーとすると、その日の書き込みを 一定範囲 に設定した範囲分、パーティション間で分散することができる。
例えば、1~20 の乱数を設定した場合、とある日のパーティションキーはランダムに 20 種類に振り分けられる。さらに、これらが均一に各パーティションに分散される。
ただし、読み込み時に問題が生じる。例えば、特定の日の項目を全て読み込む場合には、(<検索対象の日付>- * <乱数の種類>) 回分のクエリをなげ、結果をマージする必要がある。1~20 を利用していた場合には、クエリを 20 回発行する必要が出てくる。
計算されたサフィックスを使用したシャーディング
先ほどは乱数を利用していたために読み込み時に問題が生じたが、これを解決するためには、乱数ではなく特定の値をサフィックスに利用すれば良い。例えば、データ内に OrderId が存在し、 *特定の日の特定の OrderId* を検索するパターンが非常に多い場合には、日付と OrderId を組み合わせた値をパーティションキーとすればよい。
すると、<日付>-<OrderId> という形式になり、ある日のある OrderId が取得したい場合は、1回クエリを発行するだけで良い。
ただし、OrderId のカーディナリティが高い場合には、相変わらず *ある日付のデータ全て* を取得するためには、そのカーディナリティ分のクエリを発行&マージする必要があるので注意。
読み込み効率化のための Tips
ソートキーのベストプラクティス
ソートキーの利点は以下
適切に設定されていると、効率的にクエリが実行できる
stats-with や between 等がよく働く
データを階層的に定義すると、任意の階層レベルでクエリを実行できる
ex) 地理データ: country>region>state>city
階層的にクエリを実行可能