データベースの正規化とスキーマの透過性のどちらを優先しますか?


10

新しいコード要件が古いコードベースに浮上しました。これにより、以前は直接関連していなかった2つのユーザークラス(完全に異なるスキーマの異なるテーブルに格納されている)間の直接(内部)通信が可能になり、残念ながら、コードはほとんどオブジェクト指向に対応していません。あまり設計されていないため、親クラスはありません)。この機能を考慮しなかったこの古い設定にバッグを掛けるつもりなので、PKの衝突がないという保証はありません。

したがって、解決策は明白なようです。火で殺し、混乱したマッピングテーブル全体を書き換えます。マップを実装するための可能な方法については2つの方向性がありますが、私はDBAではないので、見逃した長所と短所があるかどうかはわかりません。

抽象化を明確にするために、異なるユーザーデータの3つのグループを検討してください:教授、管理、学生(いいえ、これは宿題ではありません。約束!)

マッピング1

(professor_id、admin_id、student_idは、それぞれのテーブルへの外部キーです)

| mailing_id (KEY) | professor_id | admin_id | student_id | 
-------------------------------------------------------
| 1001             |     NULL     |    87    |  NULL      |
| 1002             |     123      |   NULL   |  NULL      |
| 1003             |     NULL     |   NULL   |  123       |

このアプローチの+/-は、短所に対してかなり重いようです:

  • 行ごとに2つの「無駄な」フィールド
  • 2NFに違反
  • 異常を挿入/更新する脆弱性(0-1フィールドのみがNULLに設定されている行など)

ただし、プロにはメリットがないわけではありません。

  • マッピングは単一のルックアップで実行できます
  • mailing_idから特定のユーザーの「ソース」データを簡単に特定

正直なところ、私の考えでは、この考えはまったく好きではありません。

マッピング2

(MSG_ *が定義済みの定数、列挙型、または別の適切な識別子であると仮定します)

| mailing_id (KEY)  | user_type (UNIQUE1) | internal_id (UNIQUE2)| 
------------------------------------------------------------------
| 1001              | MSG_ADMIN          | 87                    |
| 1002              | MSG_PROF           | 123                   |
| 1003              | MSG_STUDENT        | 123                   |

この設定により、{user_type、internal_id}の固有の複合インデックスがより明確になり、3NFが維持され、アプリケーションコードでI / U異常をチェックする必要がなくなります。

欠点は、DBの外部で処理する必要があるユーザーソーステーブルを決定する際に透過性が少し失われることです。これは基本的に、アプリケーションレベルのuser_type値からテーブルへのマッピングになります。現在、私は(かなり強く)この2番目のマッピングに傾いています。

しかし、私は自分の限界を痛感しており、おそらく両方向の利点や障害を逃してしまったと確信しているので、私よりも賢明な考えに目を向けます。


2
あなたは見つけるかもしれない役割についてのMartin Fowler氏のアイデア面白い読み取りを。
Marjan Venema 2013

本当に面白かったです。悲しいことに、私の特定の問題への洞察はあまりありません
GeminiDomino 2013

あなたは管理者になる教授と管理で仕事を得る学生、あるいは教員として10年後に戻ってくる学生を得るでしょう。あなたはおそらくすでにそれらを持っています。あなたはそれらを別々に保つつもりですか、それとも統一しようとしますか?
エリン

役割は単なる例ですが、私はあなたの要点を理解しています。実際には、ユーザーが役割を切り替えたとしても、ユーザーはとにかく個別のレコードとして残ります。
GeminiDomino 2013

もしあなたが最初の段落を言い換えれば素晴らしいと思います。それは少し不明確です。つまり、問題があることは明らかですが、それが何であるかは十分に明確ではありません。
TulainsCórdova16年

回答:


1

あなたの2番目のアイデアは正しいものです。 このアプローチでは、3つの衝突するキースペースを統合するために必要なすべてのマッピングを実行できます。

重要なのは、宣言的な制約を使用するために必要な一貫性のほとんどをデータベースに課すことです。

必要以上のコードがすでにあるので、統合されたキーリストの整合性を保つために絶対に必要なコードを追加しないでください。データベースエンジンに、本来の目的で実行させることを任せましょう。

であなたに不快感を与えている「問題児」マッピング2は、あるUSER_TYPE列。この列は、INTERNAL_IDユーザータイプごとに1回だけ表示されるようにするために重要です。認識しているコードが必要になるのUSER_TYPEは、マッピングテーブルに対して挿入と削除を行うコードだけです。これはかなりよくローカライズできます。マッピングテーブルのコンテンツが維持されるコード内の単一のポイントを作成すると想定します。この1つのスポットにデータが書き込まれる追加の列は大した問題ではありません。本当に避けたいのは、データが読み込まれるすべての場所に列を追加することです。

マッピングを使用する必要のあるサブアプリケーションのコードは、USER_TYPE各サブアプリケーションに、マッピングを1つのアプリケーション固有のユーザータイプにフィルターするビューを与えるだけで、簡単に無視できます。


3

経験から、私のお勧めは、優雅さまたは「ベストプラクティス」よりも一貫性を選択することです。これは、既存の設計に合わせて、シンプルなmailing_id, user_idフィールド構造の3 つのメーリングテーブル(役割ごとに1つ)を使用することです。

それは洗練されていませんが、いくつかの利点があります...

  1. 既存の構造と一致させることは、牧草地に出す前にこのスキーマで作業する他の誰にとっても簡単です。
  2. 無駄なフィールドはなく、存在しないものと一致するようにdbに要求していません。
  3. 各テーブルは相互にしか対応しないため、ルーチンが使用するすべてのデータを結び付けるビューを作成するのは比較的簡単です。

他の多くの人がこのアプローチに同意しないと確信していますが、正規化とベストプラクティスの主な目的は、コードをより一貫性のあるものにすることです。これにより、追跡とデバッグが容易になります。


そのアプローチの問題は、データベースがメーリングIDの一意性を強制できないことです。これは、そもそもマッピングの主な目的です。それ以外の場合は、各テーブルの個々のIDフィールドを「ユーザータイプ」インジケーターとペアにすることができます。変更なしで行われます。
GeminiDomino 2013

あなたが何を手に入れているのかはわかりますが、そのようなシステムに取り組んできたので、あなたが考慮しなかったかもしれないオプションを与えました。私が見る限り、メーリングIDはどこかを参照するためのコンテンツ(何が送信されたか、またはドキュメントを見つける方法)を必要とするため、いずれにせよ、メーリングIDは外部キーである必要があります。つまり、一意性の問題は他の場所で解決されます。読んでいると、リンクされている管理者の学生と教授のデータテーブルの構造が異なる可能性があるため、ユーザータイプフィールドに値が追加されているのがわかりません。元の開発者はこの問題にぶつかったはずですが、彼らは何をしましたか?
James Snell

「ユーザータイプ」フィールドは、その特定のレコードに関連付けるテーブルを決定します。どちらの方法でもアプリケーションレベルで処理する必要があり、それらは異なるテーブルにあるため、外部キー制約にするための良い方法はありません。元の開発者は、残念ながらこの問題をまったく考慮していないようです。そのため、このような混乱に陥っています。:)
GeminiDomino 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.