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