2021年6月第2週レポート

インプット

📝 RDBのデータモデリングについて調べてみた

今作ろうとしている社内用のWebシステムで、データのストレージとしてCosmosDBを使おうと思っています。CosmosDBはMicrosoft Azureが提供するフルマネージドのNoSQLデータベースです。社内用とはいえ、トレーニングも兼ねてデータモデリングはしっかりやろうと思っているのですが、関連ドキュメントを確認しても、RDBでのデータモデリングを前提に語られることも多いので、まずはRDBのデータモデリングについて調べてみました。

RDBのデータモデリングについては情報処理技術者試験の勉強時や過去の案件で少しかじったことはあるのですが、だいぶ期間も空いてしまっているのでおさらいも兼ねて2冊ほど本を読んでみました。

前者についてはいわゆる教科書的な書籍でしょうか。DBの論理設計と物理設計とは、テーブルの正規化手法、ER図の書き方、インデックス設計といった内容の解説が満遍なく含まれています。

後者については前書と同様、基本事項の解説も含まれていますが、より実践的というか、教科書が間違っているわけではないんだけど、実践の場では別の思考観点が必要である、といった論調となっており、前書の教科書と対比しながら解釈することができました。書籍の後半部分は演習形式となっており、ファーストフード、病院、公共料金のレセプトを見て実際にテーブル設計をやってみる、といった内容となっています。直接自分の現場と関わりがある分野ではありませんが、データ構造としては自分が扱うものと似ている部分もあり、とても参考になりました。

📝 CosmosDBのデータモデリングについて調べてみた

ここからが本番というか、今週一番自分の興味深いトピックです。

これまでAzure Table Storageをよく使っていたため、パーティションといった概念であったり、半構造化(スキーマに厳密に縛られない)といった特徴は理解していたのですが、変更フィードやストアドプロシージャの活用法などは理解できていませんでした。とりあえずデータを突っ込むだけなら出来るのですが、CosmosDBの特性を把握した上での最適な構成を組みたいと思ったので、まずは調査から入っています。

一番参考になったのは以下の資料でしょうか。

[第2回 Azure Cosmos DB 勉強会] Data modeling and partitioning in Azure Cosmos DB (Azure Cosmos DB でのデータモデリングとパーティション分割) – S/N Ratio (wordpress.com)

内容についてはMicrosoftのドキュメントにも書いてある内容かと思うのですが、いろいろなところに散らばっている内容を1つの資料に集約し、実例を交えて解説されているので非常に理解しやすい内容に見えました。

自分の中で重要だと思ったポイントを整理します。

イベントを考える

これは先ほど紹介した楽々ERDレッスンにも書いてあった内容ではあるのですが、システム上でDBへのアクセスが必要となりそうなイベントにどのようなものがあるかを洗い出す、というものです。

資料にもあるようなEコマースの例でいうと以下のような内容ですね。 - 顧客の作成 - 顧客の検索 - 製品の登録 - 製品情報の編集 - 特定のカテゴリの製品のリストを取得 - 注文の作成 - ある顧客の注文をすべて取得

CosmosDBではRDBのような外部キーを使った正規化されたデータ構造を作ることはもちろん可能なのですが、外部キーで参照した箇所に必ずデータが存在することはDB側で保証されていない、弱い参照となってしまいます。また、CosmosDBではサーバレス型のサービスであるため、DBへのアクセス回数やデータ量に応じて課金料が変わっていくため、1回の問い合わせで必要十分なデータを取得できるような構造を取るのがよいと言われています。そのため、まずはシステム上で発生するイベントを把握しておくことが後々の設計に効いてくるのだと思います。

非正規化

さて、イベントがだいたい洗い出されたらデータ構造の設計に入るのですが、まずはRDBと同じ手法で正規化を繰り返しながら論理設計をしていき、その後に洗い出したイベントやビジネスドメインの特性に応じて非正規化していくのがよいと思います。また、CosmosDB(のSQL APIベース)は分類としてはMongoDBのようなドキュメントデータベースであるため、データはJSONとして格納されます。

{
    "id": "1",
    "firstName": "Thomas",
    "lastName": "Andersen",
    "addresses": [
        {
            "line1": "100 Some Street",
            "line2": "Unit 1",
            "city": "Seattle",
            "state": "WA",
            "zip": 98012
        }
    ],
    "contactDetails": [
        {"email": "thomas@andersen.com"},
        {"phone": "+1 555 555-5555", "extension": 5555}
    ]
}

JSONをそのまま格納できるので、RDBのレコードと違ってデータの中に配列構造を持たせることができます。

これを活かして、CosmosDBのモデリングでは「データの埋め込み」と呼ばれる手法がよく使われているようです。

たとえば、ある商品について複数のタグがついている、というデータ構造をRDBで表現するとき、関連エンティティとして以下のような構造をとることがあるかと思います。

template

このような構造はCosmosDBでも作ることはできますが、ある商品についてそれに付与されているタグも取得しようとすると、内部では複数回のクエリが発生してしまいます。そこで商品についてのドキュメントの中にタグについての情報も埋め込むと次のような構造になります。

{
	"id": "1",
	"productId": "AX-001-132"
	"productName": "product A"
	"tags": [
		{
			"tagId": "A001",
			"tagName": "タグA"
		},
		{
			"tagId": "B001",
			"tagName": "タグB"
		},
	],
	"price": 100
}

このような構造にすることによって、1回の問い合わせで商品についての情報をタグ情報も含めて全て取得することができます。

このようにエンティティに他のエンティティも埋め込むかは業務上発生するイベントがどんなものなのかが重要な判断基準になります。そのほかにもデータを埋め込む基準として以下のようなものが紹介されています。

  • 1対1のリレーション
  • 1対多だけど、「多」の部分がそれほど多くないケース
  • 関連するアイテムを一緒に参照することが多い
  • 関連するアイテムを一緒に更新することが多い
  • 埋め込まれたデータが頻繁には変更されない

反対に「データの参照」といった、RDBと同じような構造を取る場合の基準としては以下のようなものが挙げられています。

  • 1対多だけど、「多」の部分が多いケース(無制限とかね
  • 多対多のリレーション
  • 関連アイテムが独立して照会される
  • 関連アイテムが頻繁に変更される

CosmosDBのデータモデリングの勘所が少しは掴めてきたような気がします。そのほかにも変更フィードとストアドプロシージャを使った整合性担保のテクニックや、パーティションキーの選択など抑えておきたいポイントが見えてきたので、引き続き調査を進めていきたいと思います。

アウトプット

目立ったものはなし

Profile
d_yama
元Microsoft MVP for Windows Development(2018-2020)
Sub-category : Windows Mixed Reality
Search