web-dev-qa-db-ja.com

テーブルデザインに関する学術的な質問

プロジェクトのデータベース設計における代理キーの使用法について、教授と議論したところです。私の教授は、主キー(自然またはサロゲート)がURLでも公開されるべきではないと主張し、自動インクリメントを主キーとして使用することは german-tank problem

私は、テーブル、たとえばUSERテーブルは、電子メールなどの固有のものを格納しないため、設計上自然なキーを持たず、URLでの使用は問題ないはずだと主張しました(これは「 exposed "?)ユーザーがリソースへのアクセスを承認されているかどうかを確認する承認ステップがあるため。私はまた、自動インクリメントの使用は、データベースのマージを必要としない規模のプロジェクト(通常、自動インクリメントが問題になる可能性がある場合)では問題ないはずだと主張しました。 Oracleのような大きなソフトウェアでも自動インクリメント(シーケンス)を使用します。

しかし、私の教授はそれを認めず、議論に列の名前を付けさえします。私の設計では、列がテーブルのIDであることは明らかであるため、テーブルの列IDの名前は[tablename]_IDではなくIDです。たとえば、USERSという名前のテーブルにID列があり、PROFILESという名前のテーブルにUSER_ID列がある場合、USER_IDが関連していることは明らかです。 USERS.IDへ(ERD図面を提示しました)。しかし、私の教授は[tablename]_IDを使用すべきだと主張しました。これは、デザインを見る人がどのIDがどのテーブルに対応するのか分からないことを教授が言っているだけなので、理由はわかりませんでした。それがERD描画のポイントではないですか?

私はそれにかなり悩んでいます、それで私のデザインが「変更されるべき」である理由に「学問的に」または「実用的な」理由がありますか?私の教授は、自分の知識や経験を使って主張しているだけだと思います。なぜなら、彼の彼女の理由は、私とはあまり関係がないからです。

編集:すべての入力をありがとうございました。 URLで公開されたIDを回避する方法について詳しく説明します。列名としてIDのみを使用すると、多くの人を混乱させる可能性があることに同意する必要があります。

1
Shira Ishikawa

2つの独立した質問が表示されます。

1)自動インクリメントされたキーをURLに公開してもよろしいですか

2)主キー列にIDまたは<TableName>_IDという名前を付ける必要があります

私はこれらの2つの質問が何らかの形で関連しているとは思いません。

広告1:あなたの教授は良い点を持っています。あなたがビジネスであれば、競合他社はサインアップするだけでユーザーの総数を確認でき、一定の間隔で複数回サインアップすることで成長を観察できます。あなたはほぼ間違いなくそれを望んでいません。重要な場合もあれば、重要でない場合もあります。

広告2:これは主に慣習の問題であり、どちらの方法でも重要な議論はありません。最も重要なのは、一貫性を保つことです。一部の古いデータベースには、列名がallテーブル全体で一意である必要があると考えられます。これは、すべての列名にテーブル名をプレフィックスする規則の起源です。しかし、その制約はもはや存在しないので、その理由のためにそれに従うことは貨物養殖になるでしょう。

3
JacquesB

質問は、いくつかの関連する(ただし、最終的には別個の)質問で構成されます。

uRLで使用しても問題ありません(これは「公開」と見なされますか?)

「公開する」とは「外の世界に知らせる」ことです。 URLは、リソースにアクセスするために外部の世界で具体的に使用されるため、実際に値を公開しています。

値を公開することの主なポイントは、コンシューマーに値を知ってもらう必要があることです。コンシューマーがこの値を知っている場合、コンシューマーと調整しなくても、値を上げて変更することはできません。これは煩雑なプロセスになる可能性があるため、回避する必要があります。

しかし、私の教授は、[テーブル名] _IDを使用するべきだと主張しました。これは、デザインを見る人はどのテーブルのどのIDであるかわからない、と教授が言い続けているためです。それがERD描画のポイントではないですか?

エンタープライズグレードのアプリケーションの場合、すべてのフィールドとその名前と目的を思い出すことはできません。また、フィールド/列の名前を使用するたびにERDを簡単に処理することもできません。

このように考えてください。あなたの側にシソーラスと辞書があるからといって、私が書くすべての文(同じメッセージを伝える)が、私が書いた他のすべての文とまったく同じように理解しやすいというわけではありません。ドキュメント(シソーラス/辞書)を掘り下げることなく、すぐに理解できる言語を使用すれば、はるかに効率的です。

同じ効果を得るには、[table name]_[PK column name] FK列名として、このFKが参照しているPKをすぐに通知します。
アンダースコアは無視していることに注意してください。申し立てをしたくないのは聖なる戦争です。アンダースコアは使用しない傾向がありますが、実際の距離は異なる場合があります。

これは厳格な規則ではありませんが、開発者の生活を大幅に楽にする慣習です。

自動インクリメントを主キーとして使用するのは悪い習慣です。ドイツ戦車の問題などが原因です。

間違いではありませんが、ドイツ戦車の問題は、平均的なアプリケーションには特に関係ありません。また、GUID-などの非順次型を使用すると簡単に回避できます。分散型システムでの衝突を回避するなど、いくつかの理由で整数よりも推奨されます。これについてはすでに触れました。 :

私はまた、自動インクリメントの使用は、データベースのマージを必要としない規模のプロジェクトには問題ないはずだと主張しました(通常、自動インクリメントが問題になる可能性がある場合)

...しかし、アプリケーションが今日分散して実行されないからといって、明日分散されて実行されないという事実のために、あなたはあなたがあなたが知ることができない部分をごまかしました。

最初からGUIDをすでに使用している場合、intを使い始めた場合よりもはるかに効率的にアプリケーションをスケーリングでき、分散システムからの衝突に対応するためにコードベースをリファクタリングする必要があります。

ソフトウェア開発では、何かが変わる可能性とそれを説明する(または無視する)コスト(労力/時間/技術的負債)について合理的な判断を下す必要があります。そうする能力には経験が伴います。これについてのあなたの光沢に基づいて、私はあなたが非学術的環境でまだ多くの実際的な経験を持っていないことを学んだと推測します。

私の教授は、主キー(自然または代理)がURLであっても公開されるべきではないと主張しました

はい。ただし、アプリケーションの範囲がここで非常に重要であることは言及していません。実装の努力は常に考慮される必要があるものであり、高努力の実装が非常に実装する価値があるかどうかは、実装しようとしているアプリケーションのコンテキストに依存します。

しかし、それは理にかなっています。注文の履歴があるWebショップがあるとします。注文番号は12345であるとお客様に伝えました。その参照番号は変更されません。 (何らかの理由で)データベースを削除して再作成するとすると、PKは異なる場合がありますが、注文番号は変更されるべきではありません(それ以外の場合、顧客は注文を参照できなくなります)。ここでの唯一の論理的な結論は、注文番号がPKではない(その逆も同様)ことです。

とはいえ、一部のシステムでは、PKとIDを分離している場合でも、これらの2つの値を引き起こすイベントに(まだ)ヒットしていないため、これら2つは常に同じ値を含む可能性があります新しいエントリを追加するときに同期が外れる。

私は、テーブル、たとえばUSERテーブルは、電子メールなどの固有のものを格納しないため、設計上自然キーを持たず、URLでの使用は問題ない(これは「公開」と見なされますか?)ユーザーがリソースへのアクセスを許可されているかどうかを確認する許可ステップがあります。

承認は認証と同じではありません!

  • 認証=これは誰ですか?ボブです。
  • 承認=ボブはこのデータを表示できますか?はい。

承認は認証後にのみ発生しますが、これはそれらを単一のblobにまとめる必要があるという意味ではありません。これは、「承認ステップがあるため」というコメントが、現在実行していることを示唆しています。

ユーザーを認証するには、まずユーザーを識別し、それらを識別するには、主張するユーザーを識別できるように参照できる必要があります。つまり、すべてはユーザーを参照することから始まります。

上記と同じロジックがWebショップの例で適用されます。ユーザーをPKで参照する場合、データベースを削除して再作成すると、すべてのユーザーのPKが変更されている可能性があり、それを修正するにはコストがかかります。

Oracleのような大きなソフトウェアでも自動インクリメント(シーケンス)を使用します。

何かが存在するからといって、それが良いとは限らない。特にエンタープライズソフトウェアの分野では、下位互換性が主な機能です(Oracleは特に下位互換性を推奨しています)。これは、互換性の理由で保持されている古い機能も表示されることを意味します。

Int PKが完全に古くなっていると言っているのではありませんが、存在しているからといって、それが正しい方法であることを意味するに違いないというあなたの提案に反対しています。

4
Flater

あなたの教授は、実用性について忘れられている特定の潜在的な問題について人々に教えることに慣れているようです。機能することを実行し、より良い何かを見つけた場合は心を変える準備ができている必要があります。とはいえ、彼があなたに教える必要のあるすべての潜在的な問題を認識する必要があります。

この場合、誰かがIDからユーザーの総数を推定できるかどうかは問題になりますか(特に、多くの企業がマーケティングでその情報を明示的に提供しているため)。

URL内のIDは、ハッカーが他の人になりすますために変更するだけでひどい場合がありますが、本質的に悪いわけではありません。自動インクリメントIDが問題を引き起こす可能性がある場合もありますが、完全に許容できる場合も多くあります。このページのURLにはIDがあり、自動インクリメントされているようです。アマゾン、eBayおよびYouTube(おそらく)は、システムの規模に応じて自動インクリメントIDを必要とします。

個人的には、IDフィールドがすべてのテーブルで同じように呼び出されるようにしています。 SQLでテーブルを明示的に(Users.ID)明示的に指定することと暗黙的に(User_ID)を指定することの間に実用的な違いはありませんが、スケーラブルな命名方式ではありません。 Bookオブジェクトには、AuthorIDの代わりにAuthor_User_IDフィールドが必要になり、最終的にUser_Report_Expression_Condition_TimeLimit_Unitsというフィールドができ、最終的に名前の長さに達する制限。

また、クラスの多くに同じ名前のフィールドがある場合、使用できる可能性のあるインターフェースを発見し始めています。

ただし、同意しない場合でも、組織のコーディング標準に固執する必要があります。この場合、教授はおそらく、あなたが教えられたことを理解したことを証明することを望んでいるだけでしょう。多くの場合、後で何が起こるかについて議論しているだけのスタイルについて意見の相違があることに気づくでしょうが、それは本当に重要ではありません。要点を述べて次に進むと、「いつか言ったように」と言うことができるかもしれませんが、本当に重要なことのためにエネルギーを節約できます。

2
Robin Bennett

これらのいくつかは個人的な好みです。個人的には、主キーにidという名前を付けると、特に複数の外部キーを含む可能性のあるテーブルで、見つけやすくなります。しかし、そうでないと感じたグループで働いていれば、そのグループに同調します。自分だけではなく、他の人が読むソフトウェアを作成します。

セキュリティ関連の設計決定に関する限り、それらは時々少し迷信的に見えるかもしれませんが、ソフトウェアが将来どのように変化するかを予測することはできません。設計するだけでなく、今日は安全です。推論に慣れていない誰かが一見無関係な変更を加えた場合、またはコードを別のコンテキストで何をするかの例として使用した場合でも安全になるように設計します。その人は、6か月後にもあなたになることができます。

そのため、一般に、証明の負担は、安全性の低いオプションを実行したい人にあります。なぜneed自動インクリメントキーであるか、またはURLでキーを公開するのかを証明する必要があります。できない場合は、より安全な将来性のあるオプションを選択する必要があります。それはあなたがそれを考えていなかったので、そして抽象化の追加のレイヤーまたは2つを必要とするので、それはより多くの仕事のように感じますが、それは将来的にそれを変更するよりもはるかに少ない仕事です。

レイヤーの観点からセキュリティを考えてください。あなたが取り組んでいるのは、攻撃者が最初に通過する必要があるレイヤーではないかもしれませんが、他のレイヤーが危険にさらされている場合に攻撃の影響を最小限に抑えるために重要です。

2
Karl Bielefeldt

連続したIDについて。機密情報を公開していますか?サードパーティは、各IDに対してスクリプトを順番に実行することでインテリジェンスを取得できますか?それらは懸念事項です。

機密情報がそこに公開されていない場合-機密とは、危害を加えるために使用される可能性のあるすべてのものを意味します-おそらく問題ではありません。

セキュリティ監査では、連続したIDを持つURLが含まれていてもよい理由(および新しいフィールドが追加されたときに将来的に問題にならない理由)を、連続したURLがない場合に正当化する必要はありません。 ID。

実行しないことをお勧めします。そして、なぜ良い実践を教えないのですか?

連続したIDには、エンジンごとに異なる可能性のある他の潜在的な問題があります。たとえば、最後に挿入されたIDを取得するデータベースエンジン固有の手段に依存します。連続した最大値に達する可能性があります。データベースを別の環境に移動するときに自動インクリメントが正しく機能するように、追加の手順を実行する必要がある場合があります。 、およびパフォーマンスの問題が発生する可能性があります。


フィールド名については、先生たちにもその議論がありました…結局、私は問題を理解するようになりました:結合。したがって、テーブルに結合し、フィールドを使用する述語で結果をフィルタリングします。テーブルの指定を忘れることは非常に簡単で、同じ名前のフィールドがある場合は…

データベースエンジン(または静的チェック)が文句を言い、テーブル名を指定するように強制する場合、それは問題ではありません。一方、選択する場合(結合の左側など)、問題が発生します※。あなたのコードは壊れやすく、機能しているように見えるかもしれませんが、それは運が良かっただけで、より多くのデータ、または結合を変更したリファクターなどでバグが表示されます。

※:2つの問題があります。これをエラーとして報告しない、非常に古いまたは非常に不明瞭なエンジンを使用している必要があります。より良いものを使用してください。

外部キーのフィールドの名前を一致させる必要はありません。また、すべてのシステムに、最新の図が表示されているわけではないことにも注意してください。

2
Theraot

ここにはさまざまなアドバイスがあり、もう少し詳細に値する良い質問をしていると思います。ここから始めましょう:

私の教授は主キー(自然または代理)は決して公開されるべきではないと主張しました

これは本当に良いアドバイスであり、あなたはこれに従うべきです。他の回答ではこれについて詳しく説明しますので、詳しくは触れませんが、キーを公開するときは、他の人、システム、組織にキーを気にかけてください。これにより、データベース管理に関する柔軟性が大幅に制限されます。人々に伝えるIDを正規のIDとは別にしてください。

自動インクリメントを主キーとして使用することは悪い習慣です。ドイツ戦車の問題のようなもののため、これは悪い習慣です。

これは私にとって何か不確かなところです。キーを公開していない場合、またはキーを使用したレコードへのアクセスをサポートしていない場合は、キーがシーケンシャルであるか、この種のシステムに関してディスク上の物理的な場所よりも重要ではないかどうか。シーケンシャルキーを使用している場合、この問題だけで、キーが公開されません。

GUID(UUID)を主キーとして使用するべきであるというアドバイスについて、私はいくつかの不安があります。まず、すべてのUUIDが等しく作成されているわけではないことを理解することが重要です。 [〜#〜] uuid [〜#〜] には4/5の異なるタイプがあり、そのうちの1つだけが純粋にランダムです。他のタイプのいずれかを使用している場合、同様の値で開始および終了する多数のIDが存在しますが、IDの中央部分は非常に異なります。過度に広いスペースと組み合わせると、これは一般的なインデックス作成戦略にとって問題になります。バージョン4のUUIを使用している場合でも、必ずしも明確であることを意味するわけではありません。私はこの分野の専門家ではありませんが、これについては多くの論争があります。これがそのような debate の1つです。

ランダムなUUIDの使用に関する一般的な控え目は、それらが大量のインデックスの断片化と大きなインデックスサイズを引き起こすことです。ほとんどが99%以上の断片化を引用しています。 (特定の制約の下で)それらの使用を支持する上記のリンクの答えでさえ、これが事実であると断言します。

これは(かなり古い)主題に関する記事です: GUID vs INTの議論 。これには、ランダムなUUIDの使用に関連するいくつかのパフォーマンスとスペースのペナルティに関するいくつかの詳細と、いくつかの潜在的な利点があります。

ランダムなGUIDを主キーとして使用しないことをお勧めしませんが、その影響についてDBA(またはデータベースの専門家)と話し合うことなく、全面的にそれらを使用するのはためらいます。

データベースのマージに関連する懸念についての1つの注意。主キーを秘密にしておけば、これはそれほど大きな問題ではありません。より大きなデータベースを取り、最大のキーを見つけます。それを小さなデータベースのキーに追加すると、衝突が解消されます。ランダムな16バイト値を使用せずに複数のデータベース間の衝突を回避するために使用できる他の多くの同様のアプローチがあります。

最後に命名について:私は個人的に、すべてのテーブルで「id」または「key」を主キーとして使用し、テーブル名を使用して外部キーを定義する方法(「foo_id」など)を好みます。しかし、このアプローチは非常に一般的ではなく、私が理解していない理由により、人々はそれに強く反対しています。参照するテーブルが誰にもわからないという主張は、ばかげたIMOです。すべてのテーブルがキーとして「id」を持っている場合、それがどのテーブルに属しているかを伝えるためにid列名を必要とせず、話しているテーブルを知る必要があるだけです。私はpkがどのテーブルでも何であるかを知っています。それは 'id'です。いずれにせよ、データベースでの冗長なネーミングは宗教であり、おそらく闘う価値はありません。冗長部門の部門に対するあなたの無益な抵抗は、無益な抵抗です。

1
JimmyJames

コンピュータのために列名を選択することはありません。コンピュータは何らかの方法を気にしません。私たちは、私たち自身と将来私たちのコードを読まなければならない人々の両方にとって、人間の生活を楽にする名前を選択します。私の経験では、[tablename] _idという名前の主キーを使用すると、より簡単になります。

PROFILE.USER_ID = USER.IDを指定する例では、どちらの命名規則でもわかりやすいクエリが生成されることは自明のようです。しかし、これは単純な条項であり、結局簡単なことは簡単です。複雑なシナリオではどのように対処しますか?

テーブルに同じPKを参照する複数のFKが含まれている場合、参照されるテーブルにはエイリアスを設定する必要があります。これらのエイリアスは、クエリ内のテーブルの目的を反映する必要がありますが、多くの場合は反映されません。さらに、エイリアスのスコープはクエリに設定されているため、選択したエイリアスがクエリごとに、開発者ごとに変わる可能性が高くなります。したがって、明らかなコードPROFILE.USER_ID = USER.IDP.USER_ID = U.IDに変わります。 「U」がテーブル「USER」を参照すると想定しますが、これは自動的には明らかではなく、クエリサイズが大きくなるにつれて相互参照はますます扱いにくくなります。厳密な命名規則とデータモデルのドキュメンテーションがないと、エイリアスが何を表しているのかを暗黙に理解できなくなり、クエリを理解するのが難しくなります。

複数のFKがあると、混乱の機会が増えます。たとえば、ABC.EDITOR_ID = DEF.ID AND ABC.PRESENTER_ID = GHI.IDです。コードを理解するには、ドキュメントを(最新であることを願って)調べ、EDITOR_IDとPRESENTER_IDの両方がUSER.IDを参照していることを確認します。そのPKがUSER.USER_IDという名前であった場合、コードはより自己文書化されます。 ABC.EDITOR_ID = DEF.USER_ID AND ABC.PRESENTER_ID = GHI.USER_ID。 (はい、それらは貧弱なエイリアス名ですが、それが私のポイントです。)

すべてのテーブルに列「ID」がある場合、サイトの読み取りで「ID」を使用してコードをサニティチェックすることは不可能です。エイリアスは、おそらくネストされたサブクエリとCTEをたどって追跡する必要があります。これはトリッキーです。

すべてのテーブルにIDが含まれているため、コンパイラーは誤った別名を検出することもできません。エイリアスGHIが実際にテーブルPAYMENTを参照するとします。上記は論理エラーですが、構文エラーではありません。ただし、フルネームの同等のものは検出が簡単です。

ABC.PRESENTER_ID = GHI.USER_ID  -- compile error
                                -- GHI references PAYMENT, likely doesn't have column USER_ID

ABC.PRESENTER_ID = GHI.PAYMENT_ID  -- code review error, easy to see the discrepancy
0
Michael Green