web-dev-qa-db-ja.com

自己参照テーブル、良いか悪いか?

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

自己参照のparent_id列ukを持つ1つのテーブル-ロンドン(london parent id = UK id)

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

私の好みは、必要な数のサブ領域に簡単に拡張できる1つの自己参照テーブルです。

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

39
NimChimpsky

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

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

42
Oded

ネクロマンシング。
正解は次のとおりです。それは、どのデータベースエンジンとどの管理ツールに依存します。

例を作ってみましょう:
レポートテーブルがあります。
そしてレポートは親(カテゴリのようなメニューポイント)を持つことができ、
そして、その親自身が親を持つことができます(例:利益センター)、
など、無限に。

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

結果の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

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

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

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

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

ただし、適切なツールを備えた適切なデータベース管理システム(PostgreSQLなど)では、これは問題になりません。あなたがあなたのRDBMS(私はあなたを見ている、Microsoft; Oracle =?)、および/またはそのツールベルトに多額の費用を払っているからといって、それが適切にプログラムされていることを意味するのではありません。また、オープンソース(MySQLなど)も、このような素晴らしい特徴に免疫を与えません。

古いことわざが言うように、悪魔は細部にあります。

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

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

7
Quandary

関係が実際には階層関係であり、ネットワーク関係ではない場合(たとえば、部品表は階層関係ではなくネットワーク関係である場合)は良い考えです。

クエリに時間がかかる場合があります。物事をスピードアップするには、クロージャーテーブルを使用できます。

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

1
Neil McGuigan