ドキュメントの設計
スキーマレスが売りのドキュメント指向型データベースであっても、ドキュメントのデータの持ち方・モデリングについて検討する必要があります。
一般的にドキュメント指向型データベースでは、ある関心事に関連する情報を集約し、1つのドキュメントとして保持するデータモデリングをとります。例えば、本の作者の情報と著書の情報をひとまとめにしたドキュメントを作ったりします。
データ間のリレーションを持たないことでスケーラビリティを確保するNoSQLの特性を活かすため、Cosmos DBに関しても基本的にはこの考え方にのっとって設計を進めることになります。
しかしながら、Cosmos DBはドキュメントをまたぐトランザクションをサポートしています。このため、データの整合性確保のために1つのドキュメントに全ての情報を埋め込む必要がなく、この点はドキュメントの設計にも大きく関わってきます。
ドキュメントに全て含めるか/参照を使うか
ここでは、ドキュメントに全ての情報を埋め込む方式を「埋め込み型」、キーとなる情報を使って異なるドキュメントの情報を参照する方式を「参照型」として、それぞれの特性について説明していきます。
(1)埋め込み型
埋め込み型は、RDBの言葉でいうところの非正規化にあたる方式です。1つのドキュメントに全ての情報が含まれていることで、関連する情報をJOIN句を使用して集約する操作が不要となり、読み取りのパフォーマンスが向上します。
以下のリスト1~3は、本のオンラインショッピングサイトにおけるデータのサンプルです。
著者を表すドキュメント(エンティティ)に著書と名言のリストを含めることのできる埋め込み型JSONを表しています。このようなドキュメントの場合、著者に関連する情報全てをJOIN句なしの1つのクエリで取得することができます。
{ "id": "001", "auther": "Marcus Tullius Cicero", "books": [ { "title": "De finibus bonorum et malorum", "isbn": "9781332448715", "description": "Lorem ipsum dolor sit amet," } ], "quotation": [ "Lorem ipsum dolor sit amet", "consectetur adipiscing elit", "sed do eiusmod tempor incididunt" ] }
埋め込み型は、ドキュメントに含まれる情報の更新頻度が低く、さまざまな条件で参照される場合に有効なケースです。
例えば上のドキュメントでは、作者名、本のタイトル、ISBN、名言(の一部)などで検索することができます。
しかし、ここで本に対するユーザーレビューもこのドキュメントに保存できるよう、修正が発生した場合にはどうなるでしょうか。関連する情報に明細データの様なトランザクションデータが含まれると、ドキュメントが頻繁に変更されたり、際限なく増大したりする可能性が出てきます。その場合は埋め込み型ドキュメントに対して書き込みと読み込みの双方でコストが増加することになってしまいます。
このようなデータモデルの場合は、参照型のモデリングを検討します。
(2)参照型
参照型は埋め込み型の逆、正規化にあたる方式です。この方式をとることで、1件あたりの書き込みのパフォーマンスが向上します。
参照型では、関連するデータが頻繁に変更されたり、際限なく増加したりする場合でも、参照元のエンティティが影響を受けることはありません。
一方で、ドキュメントを取得しようとした際に複数のドキュメントを検索する必要があります。結果的に読み取り性能が下がることを許容できるかどうかが、参照型を選択するポイントとなります。
また、RDBと異なり外部キー制約がCosmos DBにはないため、関連データを必ず参照できるかは保証できません。
アプリケーションでの存在チェックの実装や、Cosmos DB上のトリガーやストアドプロシージャを使用したチェックなどで対応する必要があります。
以下のリスト2および3は、お掃除ロボットの基本情報(マスタデータ)と、掃除中に発生したイベントログ(トランザクションデータ)を、異なるデータとして保持する参照型JSONを表しています。
{ "deviceId": "A001", "deviceInfo": "cleaning robot" }
{ "deviceId": "A001", "logId": "001", "message": "[INFO]cleaning living room..." } { "deviceId": "A001", "logId": "002", "message": "[DEBUG]abcdefg" } ・・・・・・ { "deviceId": "A001" "logId": "999", "message": "[ERROR]battery empty!!!" }
ログデータのように大量かつ頻繁に発生するデータは、マスタデータと関連付けができる情報(この場合は「deviceId」)を持ち、別のドキュメントとしてそれぞれ保存していくことで、マスタデータ側のデータ更新を避けつつ高速にデータを書き込むことができるようになります。
データサイズ・RUの見積もり
第1回で説明した通り、Cosmos DBでは使用したデータ容量と、設定したRUの値を基準に課金額が決まります。
取り扱うデータがどの程度のボリュームになるか、要求されるスループットがどの程度であるかを事前に想定することは、Cosmos DBのプランを決定する際の重要な判断材料になります。
既にデータのモデリングが行われており、サンプルとなるJSONが用意できる場合は、要求ユニット計算ツールを使って確度の高い見積もりを行うことができます。
要求ユニット計算ツールの使い方については、第1回のコラムをご参照ください。
RUに影響を与える要素
RUの増減に関わってくる要素には表2ものが含まれます。
要素 | RUとの関連 |
---|---|
ドキュメントサイズ | 1ドキュメントあたりのサイズが大きい場合、データの読み取り・書き込みのRUも増える |
インデックス作成ポリシー | インデックスを作成するプロパティを減らしたり、インデックス作成を非同期に行ったりするとRUが抑えられる(インデックス作成ポリシーについては後述) |
ドキュメント内のプロパティ数 | デフォルトではドキュメントの全てのプロパティに自動でインデックスが作成されるため、プロパティ数が増えるとRUも増える |
整合性レベル | Cosmos DBの一貫性レベルのうち、強い一貫性を保障する2つのレベル(Strong・Bounded Staleness)を設定している場合、読み取りのRUが増える |
クエリ | クエリのコストが高い場合、RUも多く消費する |
スクリプト | ストアドプロシージャ、トリガーで実行する操作が複雑である場合、RUも多く消費する |
Cosmos DBの一貫性レベルは5種類から選択することができます。これは、他の分散型データベースが取り入れている2種類(厳密な整合性と結果整合性)の一貫性レベルより、きめ細やかに調整できることを意味します。
Cosmos DBの一貫性レベルの詳細については、以下のドキュメントを参照してください。
TTL(Time To Live)を使ってデータを自動的に削除する
Cosmos DBにはTTL(Time To Live)の機能があります。これは、ドキュメントに有効期限を設定して有効期限を経過したドキュメントを自動で削除することができる機能です。
一定期間のみ必要な情報(ログ、ユーザーセッション等)を多く扱う場合などはTTLを設定することで、有効期限が切れたドキュメントをCosmos DBのストレージから自動で削除するため、ストレージの使用量を節約する効果があります。
Cosmos DBのTTLでは、コレクションレベルと、ドキュメントレベルで有効期限を設定することができます。これらは、AzureポータルまたはSDKを使った実装で設定していきます。
コレクションレベルの有効期限では、コレクション配下の全てのドキュメントに共通のルールを定義します。具体的には、削除するまでの有効期限を秒単位でコレクションに対して設定します。
Azureポータル上では、「Azure Cosmos DB」の画面から、データベースアカウントを選択し、「設定」メニュー内でTTLの設定を切り替えることができます。
例として、24時間後(=86400秒後)に有効期限切れとなるように設定を入れたものが図2です。
ドキュメントレベルの有効期限では、ドキュメント内にTTLという名前のプロパティを用意することで、最終更新時間(_tsプロパティの値)からn秒後に削除するように指定することができます。TTLプロパティに何も設定をしなかった場合は、コレクションレベルのルールが継承されます。
図3は、あるドキュメントに「ttl」プロパティを追加し、10分後(=600秒後)に有効期限切れとなるように設定した例です。