はじめに
他のより単純なデータストレージオプションに対するデータベースの主な利点の 1 つは、情報を秩序正しく、簡単にクエリ可能な構造で保存できることです。これらの機能は、データベースが保存するデータを記述するためにスキーマを実装しているという事実から派生しています。
データベーススキーマは、データベース内のデータの形状と形式の設計図として機能します。リレーショナルデータベースの場合、これにはデータのカテゴリと、テーブル、主キー、データ型、インデックス、およびその他のオブジェクトを介したそれらの接続の記述が含まれます。NoSQL スキーマでは、これは多くの場合、最も重要な予測されるクエリパターンに従ってデータを整理することが含まれます。
どちらの場合でも、データベースのスキーマの価値と、ニーズに合わせて最適に設計および最適化する方法を理解することが重要です。このガイドでは、データベーススキーマとは何か、遭遇する可能性のあるスキーマのさまざまなタイプ、それらが重要な理由、および独自のスキーマを設計する際に留意すべき事項に焦点を当てます。
データベーススキーマが重要な理由
データベーススキーマは多くの理由で重要です。
データのソースやアプリケーションに関係なく、データにはほぼ常に何らかの規則性があります。一部のデータは非常に規則的であり、つまり、すべてが同じパターンで記述できます。一部のデータははるかに不規則ですが、それでも、そのメタデータ、つまりデータ自体に関するコンテキストデータは、多くの場合、依然として規則的です。
データベーススキーマは、データが何であるか、およびその操作方法をデータベースに伝えます。データベーススキーマは、データベースエンジンがこれらのパターンを理解するのに役立ち、これにより、データに制約を適用したり、クエリされたときに適切な情報で応答したり、ユーザーが要求する方法でデータを操作したりできます。
優れたスキーマは、暗黙的な情報を減らし、システムとそのユーザーに可視化する傾向があります。リレーショナルデータベースのスキーマは、情報の冗長性を減らし、データの一貫性を確保し、関連データにアクセスして結合するために必要な足場と構造を提供できます。非リレーショナルコンテキストでは、優れたスキーマは、ストレージ形式をアプリケーションに不可欠なアクセスパターンに合わせることで、高いパフォーマンスとスケーラビリティを実現します。
物理スキーマと論理スキーマの定義
さらに進む前に、いくつかの定義を紹介する必要があります。潜在的に混乱を招く 2 つの用語は、物理スキーマと論理スキーマです。これらの 2 つの用語は、使用されるコンテキストに応じて異なる意味を持つ可能性があります。
この記事の目的のために、主にデータベーススキーマの設計時における論理スキーマと物理スキーマについて説明します。
データベーススキーマの設計時
データベーススキーマの設計について話すとき、論理スキーマは、データをさまざまなカテゴリに編成し、データのプロパティを定義し、データベースアイテムに最適な構造を決定するための一般的な設計です。この一般的なドキュメントには実装の詳細がなく、したがってプラットフォームに依存しません。これは設計図として捉えられ、さまざまなデータベースシステムに実装できます。
同じコンテキストでは、物理スキーマは、実装固有の詳細が検討される設計プロセスの次のステップとして認識されます。さまざまなエンティティ、制約、キー、インデックス、およびその他のアイテムの名前が識別され、論理スキーマにマッピングされます。これにより、特定のデータベースプラットフォームを使用した実装のための具体的な計画が提供されます。
このコンテキストでは、論理スキーマと物理スキーマは設計プロセスの異なる段階です。プロセスの目標は、まずデータの抽象的な品質をレイアウトし、後でその編成を、使用したいデータベースシステムのツールセットと言語にマッピングすることにより、要件のセットから実装計画を反復的に開発することです。
データベースアーキテクチャについて議論するとき
物理スキーマと論理スキーマがデータベースに関して見られるもう 1 つのコンテキストは、実際のデータベースソフトウェアの物理アーキテクチャと仮想アーキテクチャです。
このコンテキストでは、論理スキーマは、ユーザーが操作する可視データベースエンティティを指します。つまり、テーブル、キー、ビュー、インデックスなどのオブジェクトは、ユーザーがデータベースソフトウェアを使用して作成および操作する抽象化です。システム内のこれらのアイテムのレイアウトは、データベースが提示する論理スキーマの一部です。
同じコンテキストでは、物理スキーマは、データベースソフトウェアがファイルシステムと対話するときに、データ、ファイル、およびストレージを処理する方法を指します。たとえば、データベースアーキテクチャの物理スキーマは、システムがデータベースごとまたはテーブルごとに別々のファイルを保存するかどうかを決定し、それらを複数のサーバーにどのようにパーティション分割できるかを決定できます。
静的スキーマと動的スキーマ
スキーマをリレーショナルデータベースと非リレーショナルデータベースの違いを明確にするのに役立つもう 1 つの重要な分類は、静的スキーマと動的スキーマの違いです。
静的スキーマは、一般的にリレーショナルデータベースに関連付けられているタイプのスキーマです。それらは、システムに受け入れられるためにデータが従う必要のある形状の定義として事前に定義されています。静的スキーマは、データベースシステムが入力に対して検証できる目的の状態のアサーションであるため、データベースシステムは静的スキーマを使用するときにこれらのパターンを適用できます。
対照的に、動的スキーマは、非リレーショナルコンテキストではるかに普及しています。動的スキーマはそれほど厳密ではなく、事前に考えられた組織構造が欠落している可能性があります。代わりに、動的スキーマは、システムに入力されたデータの品質に基づいて出現します。多くの非リレーショナルデータベースは、任意の内部構造で情報を保存できますが、ほとんどの現実世界のユースケースでは、規則的なパターンが出現する傾向があります。
動的スキーマは創発的な構造であるため、データベースシステムはそれらを適合性ツールとして使用できません。ただし、ユーザーとしてそれらを理解し、それらを基に開発することは依然として非常に重要です。データが一般的な意味でどのように見えるか、およびアプリケーションがデータとどのように対話する必要があるかを理解することは、要件を満たし、パフォーマンスが高く、不必要な不整合を回避する構造を選択するのに役立ちます。
データベーススキーマの設計
データベーススキーマのさまざまなタイプを理解したので、プロジェクトのスキーマをどのように設計しますか?効果的なスキーマを設計するには、問題領域とデータを使用するシステムを十分に理解するだけでなく、思考と実践が必要です。
設計プロセスは、スキーマを設計するデータベースのタイプによって大きく異なります。具体的には、静的スキーマの設計プロセスは、動的スキーマの設計プロセスとは異なります。実際には、これらはリレーショナルデータベース(静的)と非リレーショナルデータベース(動的)の設計の違いに合致することになります。
一般的なヒント
リレーショナルデータベースと非リレーショナルデータベースのスキーマ設計には違いがありますが、スキーマ開発に適用できる一般的なヒントがいくつかあります。これらの多くは設計プロセスの開始に重要であるため、最初にこれらについて説明するのが理にかなっています。
データについて学ぶ
スキーマを設計する最初のステップの 1 つは、常にデータとドメインについて学ぶことです。管理する情報と使用されるコンテキストを理解せずに、優れたデータベース設計を開発することは不可能です。
最初はデータのすべての機能を把握していない可能性がありますが、システムが管理することが期待されるデータについてできるだけ多くを学ぶことは、設計に不可欠です。
答えようとするべき質問には、次のようなものがあります。
- 大まかに言って、データは何になりますか?
- 記録するのに重要な属性は何ですか?
- データセット全体のサイズはどのくらいになりますか?
- システムはどのくらいの速さで新しいデータを蓄積しますか?
- データは非常に規則的になりますか?
使用パターンを理解する
同様に、ユーザー要件を理解せずにデータベーススキーマを設計することは、他のソフトウェア設計と同様に問題があります。データが使用されるドメインの専門家でない場合は、要件について案内してくれる専門家に相談する必要があります。
次のような質問を自問する必要があります。
- 最も一般的なクエリは予測可能ですか?
- 同時ユーザーまたはクライアントの数はいくつになりますか?
- 典型的な操作とクエリによってどのくらいのデータが処理されますか?
- リクエストの大部分は読み取りクエリですか、それとも書き込みクエリですか?
- どのデータが定期的に一緒にクエリされますか?
- ほとんどの操作は、個々のレコードをターゲットにしていますか、それとも多くのレコードを集計していますか?
命名規則を開発する
重要ではないように思えるかもしれませんが、命名規則を設計して厳密に従うことは、開発と通常の使用の両方で役立ちます。
命名およびスタイリング規則は、新しいエンティティに名前を付けるときに実行する必要がある精神的な作業の量を最小限に抑えるのに役立ちます。同様に、規則により、ユーザーはスキーマ内のさまざまなアイテムにアクセスするときにパターンを安全に想定できます。一部のデータベースシステムまたはデータベースタイプには、すでに一般的な命名規則があり、それに従うことで、驚きを回避し、独自の標準を開発する必要を回避できます。
検討する必要があるスタイルと命名規則の一部
- 大文字と小文字を区別するシステムでは、大文字と小文字の文字をどのように使用する必要がありますか?
- アイテムはいつ単語の複数形と単数形のどちらを使用する必要がありますか?
- 複数語の名前は、単語をアンダースコア、ダッシュ、またはその他の区切り文字で区切る必要がありますか?
- フルネームを常に使用する必要がありますか、それとも場合によっては略語が許可されていますか?
リレーショナルデータベースのスキーマの設計
リレーショナルデータベースは、多くの場合、柔軟で汎用的なソリューションと見なされています。アドホッククエリを処理する機能により、同じデータベースがさまざまなアプリケーションとユースケースに対応できます。このため、リレーショナルデータベースのスキーマを設計する場合、最終目標は通常、データの一貫性がシステムに入る機会を最小限に抑えながら、柔軟性を促進する方法でデータを表現することです。
論理スキーマの開発
リレーショナルスキーマの設計は、前のセクションで説明したように、論理スキーマから始まることがよくあります。
実装の詳細やパフォーマンス基準に関係なく、管理するデータアイテム、それらの関係、および考慮すべき重要な属性をマッピングします。このステップは、すべてのデータアイテムを 1 か所に収集し、それらが抽象レベルで互いにどのように関連しているかをソートできるため、重要です。
特定のデータアイテムとその属性を表すテーブルのスケッチを開始できます。このマッピングプロセスは、多くの場合、エンティティ関係(または ER)モデルで最適に表現されます。ER モデルは、アイテムタイプとその属性を定義し、これらを接続して関係と依存関係をマッピングすることにより、データオブジェクトを視覚的に表現する図です。
ER モデルは、初期段階のスキーマ設計で頻繁に使用されます。これは、ER モデルが、区別するエンティティ、管理する必要のある属性、互いに関連するエンティティ、およびそれらの関係の具体的な性質を把握するのに非常に優れているためです。ER モデル図を使用して論理スキーマを表現すると、実装固有の詳細についてコメントせずに、データベース設計をどのようにしたいかについての確固たる計画が得られます。
物理スキーマの開発
論理スキーマを作成したら、次のステップは、物理スキーマ(前のセクションで説明したように)を作成して、特定の実装の詳細を把握することです。物理スキーマは、利用可能なデータベース構造と機能を使用して計画をどのようにコミットするかを正確に決定します。
最初のステップは、多くの場合、データベースエンティティを 1 つずつ調べて、主キーフィールドを決定することです。主キーは、テーブル内の各レコードを一意に識別し、異なるテーブルのレコードを一緒にバインドするために使用されます。論理スキーマの 2 つのエンティティ間にリレーションシップが存在する場合、一方のテーブルの主キーをもう一方のテーブルの外部キーとして参照することにより、物理スキーマで 2 つのテーブルを接続する必要があります。このリレーションシップの方向は、データベースを使用するときに異なるエンティティを結合できるパフォーマンスと容易さに影響を与えます。
この段階で検討するもう 1 つの考慮事項は、予測されるクエリパターンです。これらのテーブル内の一部のテーブルとフィールドは、他のテーブルやフィールドよりもはるかに頻繁にアクセスされます。これらの「ホットスポット」は、データベースインデックスの適切な候補です。データベースインデックスは、データ更新中のパフォーマンスの低下と引き換えに、一般的にアクセスされるアイテムの取得を大幅に高速化します。最初にインデックスを作成する列を決定すると、これらの懸念のバランスを取り、システム内のインデックスの最も重要な場所を定義するのに役立ちます。
データ構造の正規化
このプロセス中に、論理エンティティから特定の要素を独自の独立したテーブルに抽出する方が簡単であることがわかる場合があります。たとえば、顧客から配送先住所を抽出して、複数の配送先住所を 1 人の顧客に関連付けたり、製品注文が特定の住所を参照したりできるようにすることができます。これらの変更は、正規化と呼ばれるプロセスの一部と考えることができます。
データベース正規化は、データベースが各データを 1 回だけ表現し、不整合を引き起こす可能性のある更新を許可しないようにするプロセスです。正規化は、このガイドの範囲外である大部分の巨大なトピックですが、物理スキーマ設計プロセスの一部には、求める正規化のレベルを把握し、その目標を達成するために必要に応じてデータエンティティを変換することが含まれます。
非リレーショナルデータベースおよび NoSQL データベースのスキーマの設計
非リレーショナルデータベースの設計プロセスは、多くの場合、非常に異なります。この違いの大部分は、多くの場合、非リレーショナルデータベースは、限られた数の事前定義されたクエリで高いパフォーマンスを可能にするために選択されるという事実に起因します。
プライマリークエリの決定
非リレーショナルデータベーススキーマは、多くの場合、それらを使用するアプリケーションと連携して設計されます。スキーマは、アプリケーションの特定のニーズを反映しており、ある意味で、アプリケーションによって開発された型に適合するように設計されたカスタム構造です。
この密接な関係のため、データベースが応答するように最適化する必要があるクエリを決定することが重要です。最初のステップは、データベースが実行する必要があるクエリを把握することです。まだデータ構造がないため、これらは擬似クエリになりますが、アプリケーションが特定の操作を実行するために必要なデータを理解することが最初の目的です。
アプリケーションが実行する必要があるクエリについて十分に理解したら、焦点を当てる最も重要なクエリを選択する必要があります。これらは、アプリケーションが頻繁に実行し、待つ余裕がないクエリです。
クエリのどれが最も重要かを定義すると、データ構造が最適化する必要がある正確なアクセスパターンがわかります。データベースシステムがデータを保存および表現する方法は、データアイテムを迅速に取得および操作する能力に大きな影響を与えます。
プライマリークエリを中心に初期スキーマを設計する
最も重要なアクセスパターンがわかったので、これらのクエリに一致するスキーマの開発を開始できます。
このプロセスにおける最初のステップは、各クエリによって返されるべき正確な情報を特定することです。次に、クエリに応答するためのすべての情報を単一のエンティティに格納する場合、どのような構造になるかを概略的に示します。
たとえば、アプリケーションがデータベースにクエリを実行してユーザープロファイル情報を取得する場合、出発点はおそらく、すべてのユーザープロファイル情報が単一の場所に格納できると想定することでしょう。
可能な場合はデータエンティティを結合および重複排除する
必要な属性を特定し、各クエリに関連するすべてのアイテムを単一のエンティティに格納する場合の構造を概略的に示した後、重複がないか確認します。ここで重要な考え方は、システムが維持する個別のアイテム数を減らすために、可能な限りデータエンティティを統合することです。維持する個別のエンティティタイプが多いほど、不整合や更新パフォーマンスの問題が発生する可能性が高くなります。
これらの重複の中には、かなり明白なものもあります。あるクエリが別のクエリの属性のサブセットを返す場合は、単一のエンティティに安全にまとめることができます。
場合によっては、クエリの情報をどのようにマッピングするかを判断するのがより難しいかもしれません。非リレーショナルデータベースは、多くの場合、複数のエンティティからのデータを単一のクエリで結合することは得意ではありません。これは、リレーショナルデータベースが結合によって優れている点です。そのため、特定の属性またはエンティティが複数のクエリに存在する場合、そのデータを最適に表現する方法を選択する必要があるかもしれません。
アプリケーションがギャップを埋めることができる場所を特定する
一部のクエリでは、アプリケーションがデータベースに単一のクエリで関連情報すべてを応答させるのではなく、データ組み立ての作業の一部をアプリケーションで行う必要がある場合があります。たとえば、顧客情報とそれに関連する注文を処理する必要がある場合、注文を別のカテゴリに格納し、顧客オブジェクト内でIDによって参照することが理にかなっているかもしれません。
一部のデータベースシステムでは、オブジェクト間の参照をたどってこの情報を簡単に結合できません。代わりに、アプリケーションは最初に顧客にクエリを実行し、次に検出した注文IDを使用して、関連する注文ごとに追加のクエリを実行する必要がある場合があります。
アプリケーションコードでこれらの操作を実行すると、一部の非リレーショナルデータベースの制限を回避するのに役立ちます。これは、単一のエントリ内に大量の情報を維持しようとしたり、さまざまなタイプのデータベースオブジェクトに対してデータを何度も複製しようとしたりするよりも、多くの場合、より良い選択肢です。これらのオプションは、パフォーマンスとデータの一貫性の低下を招く可能性があります。
とは言え、アプリケーションのパフォーマンスと高速なデータベース操作をトレードオフにしていないことを確認するために、アプリケーションコードとデータベーススキーマが両方ともオンラインになったら、テストとチューニングを行うことが重要になります。経験則として、データベースの機能は情報検索と操作に高度に最適化されているため、可能な限りデータベースの機能を使用し、必要に応じてアプリケーション内で補完することが推奨されます。
適切なパーティションキーを決定する
拡張性の高い非リレーショナルデータベースの場合、ユーザーは多くの場合、パーティションキーまたはシャーディングキーを決定する必要があります。これらのキーは、パフォーマンスと応答性を向上させるために、データセットをさまざまなサーバー間で分割するために使用されます。
適切なパーティションキーを見つけることは、データとワークロードに大きく依存します。ただし、いくつかの一般的なルールがガイドとして役立ちます。
キーの分布が比較的均等なパーティションキーを選択するのが最善です。たとえば、顧客データを分散する必要がある場合、顧客の誕生月は通常、適切な分布につながります。対照的に、冬物衣料を販売している場合、製品の季節性がキーの分布に影響を与える可能性が高いため、登録月は適切なパーティションキーとは言えません。候補データにハッシュアルゴリズムを適用すると、キースペースをより均等に分散するのに役立つ場合もあります。
もう1つの考慮事項は、ワークロードが読み取り負荷が高いか、書き込み負荷が高いかです。読み取り負荷の高いアプリケーションがある場合は、関連データを可能な限り単一のサーバーに書き込むことができるパーティションキーを選択することをお勧めします。これは、関連データを取得する必要があるたびに、多数のサーバーから読み取る必要性を回避するのに役立ちます。
一方、書き込み負荷の高いワークロードがある場合は、書き込みを可能な限り多くのサーバーに分散することが望ましいことがよくあります。各リクエストが同じサーバーにデータを書き込む場合、書き込み集中型の操作でパフォーマンスが大幅に向上することはありません。
まとめ
効果的なデータベーススキーマを設計するには、忍耐、実践、そして多くの場合、多くの試行錯誤が必要です。
まず、データの外観、アプリケーションがデータをどのように使用するか、および必要なユーザビリティとデータ整合性の要件について、良いアイデアを開発する必要があります。その後、目標は、データの特定の特徴を反映し、予想されるユースケースのタイプを容易にするスキーマを開発することです。
スキーマ設計は、他のタイプの設計と同様に、反復的なプロセスです。問題空間の理解が深まり、実際のパフォーマンスデータが利用可能になるにつれて、設計を変更することを想定してください。時間の経過とともにスキーマを進化させる必要があるかもしれませんが、強固な基盤から始めることは、このプロセスを支援し、将来の劇的で破壊的なスキーマ変更の可能性を減らすのに役立ちます。
Prisma は、データモデルセクションのPrisma スキーマファイルでデータ特性を定義します。リンクされたドキュメントをチェックして、これらの概念が Prisma にどのように適用されるかについて詳しく学んでください。
また、Prisma スキーマ API リファレンスページを見て、さまざまな機能の使用方法の概要を把握することもできます。