自己参照テーブル、良いか悪いか?[閉まっている]


37

アプリケーション内の地理的な場所を表す、基礎となるデータモデルの設計は、2つの明確なオプション(またはそれ以上?)を提案します。

自己参照parent_id列ukを持つ1つのテーブル-ロンドン(ロンドンの親ID =英国ID)

外部キーを使用する1対多の関係を持つ2つのテーブル。

私の好みは、必要な数のサブリージョンに簡単に拡張できるため、1つの自己参照テーブルです。

一般に、人々は自己参照テーブルから離れますか、それともA-OKですか?

回答:


40

自己参照テーブルに問題はありません。

深い(無限?)ネストされた階層の一般的なデータベース設計パターンです。


@NimChimpsky-再帰の概念のように、この考えは一部の人にとっては難しいです。
-Oded

2
(少なくとも)Oracleには、自己参照テーブルを処理するための特別なSQL構文である「START WITH-CONNECT BY」句さえあります。
-user281377

1
@ user281377-SQL Serverはこのhierarchyidタイプを導入しました。
Oded

休止状態を使用するため、独自の特別なソースがあります
-NimChimpsky

4
@NimChimpsky-その「parent_id」列の代替として「ネストされたセットモデル」を検討することを検討してください-同じ機能を提供しますが、パフォーマンスを向上させ、階層を抽出するクエリを簡単にします。en.wikipedia.org/wiki/Nested_set_model Joe Celkoの本シリーズ「SQL For Smarties」には、ネストされたセットに関する優れたサンプルSQLがあります。
キースパーマージュニア

7

ネクロマンシング。
正解は、どのデータベースエンジンとどの管理ツールに依存するかです。


を見てみましょう。レポートテーブルが
あり、レポートには親(カテゴリなどのメニューポイント)
を含めることができ、その親自体に親(たとえば、利益センタ)を含めることができ
ます。

自己参照エンティティ/階層と同様に、標準的な再帰関係の最も単純な例。

結果のSQL-Serverテーブルは次のとおりです。

IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports 
GO



CREATE TABLE dbo.T_FMS_Reports 
( 
     RE_UID uniqueidentifier NOT NULL 
    ,RE_RE_UID uniqueidentifier NULL 
    ,RE_Text nvarchar(255) NULL 
    ,RE_Link nvarchar(400) NULL 
    ,RE_Sort int NOT NULL 
    ,RE_Status int NOT NULL 
    ,PRIMARY KEY CLUSTERED ( RE_UID ) 
); 

GO

ALTER TABLE dbo.T_FMS_Reports  WITH CHECK ADD  CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID) 
REFERENCES dbo.T_FMS_Reports (RE_UID) 
-- ON DELETE CASCADE -- here, MS-SQL has a problem 
GO

ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports 
GO

ただし、問題が発生し
ます。すべてのサブメニューポイントでメニューポイントを削除する必要がある場合、delete-cascadeを設定できません。MicrosoftSQL-Serverは再帰的なカスケード削除をサポートしないためです(一方で、PostGreSQLはグラフは循環的ではありません]。MySQLは再帰CTEをサポートしていないため、この種のテーブル構造はまったく好きではありません)。

そのため、削除の整合性/機能を爆破し、独自のコードまたはストアドプロシージャ(RDBMSがストアドプロシージャをサポートしている場合)にそのような機能を実装することを必須にします。

これは、(非自己参照)外部キー関係に従ってすべてのテーブルに対して削除ステートメントを実行することも、単純な選択を行うこともできないため、あらゆる種類の全自動動的データインポート/エクスポートを爆破することは間違いありません*そして、任意の順序ですべての行に挿入を作成します。

たとえば、SSMSを使用してINSERTスクリプトを作成すると、SSMSは外部キーを取得しないため、依存関係の親を挿入する前に、依存関係を持つエントリを挿入する挿入ステートメントを実際に作成します。 、外部キーが配置されているため。

ただし、適切なツールを使用した適切なデータベース管理システム(PostgreSQLなど)では、これは問題になりません。RDBMS(私はあなた、Microsoft、Oracle =?)、および/またはそのツールベルトに多くのお金を払っているからといって、それが適切にプログラムされているわけではありません。また、OpenSource(MySQLなど)を使用しても、このようなすばらしい特徴に耐性がありません。

古いことわざにもあるように、悪魔は細部に宿っています。

さて、このような問題を回避できなかったわけではありませんが、システムが複雑になる場合(200以上のテーブルなど)は、お勧めしません。
さらに、(ディルバートによって描かれた)通常の商用設定では、その時間は与えられません。

はるかに優れたアプローチは、より困難ですが、クロージャーテーブルです。
これには、MySQLでも機能するという追加のボーナスがあります。
一度クロージャー機能を実装すると、ほとんど時間をかけずに追加の場所で機能するようになります。


3
クロージャーテーブルに注意を向ける+1(少なくとも用語については、すでに概念を知っていました)。興味があるかもしれない他の人のための良い記事があります。coderwall.com/p/lixing/closure-tables-for-browsing-trees-in-sql
Outfast Source

1

リレーションシップが実際に階層的であり、ネットワークリレーションシップではない場合(たとえば、部品表はネットワークリレーションシップであり、階層関係ではない場合)、それは良い考えです。

照会に時間がかかる場合があります。処理を高速化するために、クロージャーテーブルを使用できます。

http://karwin.blogspot.ca/2010/03/rendering-trees-with-closure-tables.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.