자체 참조 테이블, 양호 또는 불량? [닫은]


37

응용 프로그램 내의 지리적 위치를 나타내는 기본 데이터 모델의 디자인은 두 가지 명확한 옵션을 제안합니다.

자체 참조 parent_id 열 영국-런던 (london parent id = UK id)이있는 하나의 테이블

외래 키를 사용하여 일대 다 관계를 갖는 두 개의 테이블.

필자는 선호하는 한 많은 하위 영역으로 쉽게 확장 할 수 있으므로 하나의 자체 참조 테이블을 선호합니다.

일반적으로 사람들은 자기 참조 테이블을 멀리하거나 A-OK입니까?

답변:


40

자체 참조 테이블에는 문제가 없습니다.

깊이있는 (무한?) 중첩 계층 구조에 대한 일반적인 데이터베이스 디자인 패턴입니다.


@NimChimpsky-재귀의 개념과 마찬가지로이 아이디어는 일부에게는 어렵습니다.
Oded

2
(적어도) Oracle은 자체 참조 테이블을 처리하기 위해 특수한 SQL 구성 "START WITH-CONNECT BY"절을 가지고 있습니다.
user281377

1
@ user281377-그리고 SQL Server는 hierarchyid유형을 도입했습니다 .
Oded

usign 최대 절전 모드는 자신의 특별한 소스를 가지게됩니다
님 침 스키

4
@NimChimpsky- "parent_id"열의 대안으로 "Nested Set Model"을 고려하십시오. 동일한 기능을 제공하지만 성능을 향상시키고 계층을 추출하기위한 더 쉬운 쿼리를 제공합니다. en.wikipedia.org/wiki/Nested_set_model Joe Celko의 저서 시리즈 "SQL For Smarties"에는 중첩 집합에 관한 훌륭한 SQL 예제가 있습니다.
Keith Palmer Jr.

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

그러나 문제가 발생합니다.
모든 하위 메뉴 지점이있는 메뉴 포인트를 삭제해야하는 경우 Microsoft SQL-Server 는 재귀 연속 삭제를 지원하지 않기 때문에 delete-cascade를 설정할 수 없습니다 (반면 PostGreSQL은 [ 그래프는 순환 적이 지 않다.] 반면 MySQL은 재귀 적 CTE를 지원하지 않기 때문에 이런 종류의 테이블 구조를 전혀 좋아하지 않는다.

따라서 삭제 무결성 / 기능을 사용하여 자체 코드 또는 저장 프로 시저 (RDBMS가 저장 프로 시저를 지원하는 경우)에서 해당 기능을 구현해야합니다.

이것은 (자체 참조가 아닌) 외래 키 관계에 따라 모든 테이블에 대해 delete 문을 실행하거나 간단한 선택을 수행 할 수 없기 때문에 모든 종류의 완전 자동 동적 데이터 가져 오기 / 내보내기를 의심 할 것입니다. * 임의의 순서로 모든 행에 대한 삽입을 작성하십시오.

예를 들어, SSMS를 사용하여 INSERT 스크립트를 만들면 SSMS는 외래 키를 얻지 못하므로 종속성이있는 항목을 삽입하기 전에 종속성이있는 항목을 삽입하는 삽입 문을 작성하여 오류로 실패합니다. 외래 키가 있기 때문입니다.

그러나 적절한 도구를 사용하여 PostgreSQL과 같은 적절한 데이터베이스 관리 시스템에서는 이것이 문제가되지 않습니다. RDBMS (Microsoft, Oracle =?), 및 / 또는 툴 벨트에 대해 많은 비용을 지불한다고해서 제대로 프로그래밍 된 것은 아닙니다. 그리고 OpenSource (예 : MySQL)도 그러한 훌륭한 축소에 면역되지 않습니다.

오래된 말이 진행됨에 따라 악마는 세부 사항에 있습니다.

이제 이러한 문제를 해결할 수는 없지만 시스템이 복잡 할 경우 (예 : 200+ 테이블) 실제로 권장하지 않습니다.
또한 Dilbert가 묘사 한 일반적인 상업 환경에서는 그 시간이 주어지지 않습니다.

훨씬 어려운 접근 방식은 클로저 테이블 일 것입니다.
그것은 MySQL에서도 작동하는 추가 보너스를 가질 것입니다.
클로저 기능을 한 번 구현하면 거의 모든 시간에 추가 장소에서 작업하게됩니다.


3
클로저 테이블에주의를 기울이는 데 +1 (적어도 용어는 이미 개념을 알고 있음). 관심있는 다른 사람들을 위해 좋은 기사가 있습니다. coderwall.com/p/lixing/closure-tables-for-browsing-trees-in-sql
Outfast Source

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.