programing

순환 참조가 데이터베이스에서 허용됩니까?

yellowcard 2023. 3. 21. 21:50
반응형

순환 참조가 데이터베이스에서 허용됩니까?

순환 참조는 언제 데이터베이스에서 허용됩니까?

이론적이고 실용적인 도움에 감사드립니다.

도시와 주를 고려합니다.각 도시는 주 내에 존재한다.각 주는 수도를 가지고 있다.

CREATE TABLE city (
  city  VARCHAR(32),
  state VARCHAR(32) NOT NULL,
  PRIMARY KEY (city),
  FOREIGN KEY (state) REFERENCES state (state)
);

CREATE TABLE state (
  state VARCHAR(32),
  capital_city VARCHAR(32),
  PRIMARY KEY (state),
  FOREIGN KEY (capital_city) REFERENCES city (city)
);

첫 번째 문제 - 외부 키가 존재하지 않는 테이블의 열을 참조할 수 없기 때문에 이러한 테이블을 그림과 같이 만들 수 없습니다.해결책은 외부 키를 사용하지 않고 생성한 후 외부 키를 추가하는 것입니다.

두 번째 문제 - 각 삽입에는 다른 테이블에 기존 행이 필요하므로 두 테이블에 행을 삽입할 수 없습니다.해결책은 외부 키 열 중 하나를 NULL로 설정하고 해당 데이터를 두 단계로 나누어 삽입하는 것입니다.

--Create state record
INSERT INTO state (state, capital_city) VALUES ('Florida', NULL);

--Create various city records
INSERT INTO city (city, state) VALUES ('Miami', 'Florida');
INSERT INTO city (city, state) VALUES ('Tallahassee', 'Florida');
INSERT INTO city (city, state) VALUES ('Orlando', 'Florida');

--Set one of the cities as the capital
UPDATE state SET capital_city = 'Tallahassee' WHERE state = 'Florida';

다른 레코드를 가리키는 레코드는 데이터베이스에서 유용합니다.때때로 이 기록들은 순환을 형성한다.이것은 여전히 유용할 수 있습니다.실제로 유일한 진짜 골칫거리는 구속조건을 위반하는 것을 피하는 것이다.

예를 들어 사용자 및 트랜잭션테이블이 있는 경우 사용자는 마지막 트랜잭션에 대한 포인터를 가질 수 있습니다.먼저 트랜잭션을 삽입한 후 업데이트해야 합니다.last_transaction_id올바른 값으로 설정합니다.이 두 레코드가 존재하는 동안에는 삭제할 수 없습니다.user.last_transaction_id가리키다transaction.id그리고.transaction.user_id가리키다user.id이는 트랜잭션이 없는 사용자가 null을 가지고 있음을 의미합니다.last_transaction_id또한 트랜잭션을 삭제하기 전에 해당 필드를 null로 만들어야 합니다.

이러한 외부 키 제약을 관리하는 것은 번거로운 일이지만, 확실히 가능합니다.나중에 새로운 순환 종속성을 도입하는 제약 조건을 데이터베이스에 추가하면 문제가 발생할 수 있습니다.이럴 때는 조심해야 해요.단, 사이클 내의 레코드 중 하나에 눌 가능한 외부 키필드가 있는 한 사이클은 끊어지고 레코드를 삭제할 수 있습니다.올바른 순서로 레코드를 삽입하기만 하면 일반적으로 업데이트는 문제가 되지 않습니다.

기술적으로도 가능하지만, 기록을 삭제할 때 닭고기-계란 문제를 일으키기 때문에 여러 가지 문제가 발생할 수 있습니다.이러한 문제는 종종 수동으로 FK를 폐기하고 문제를 해결하기 위해 문제를 일으키는 항목을 삭제하는 것과 같은 극단적인 조치를 취합니다.

다음과 같은 관계를 맺고 있는 경우:

create table foo_master (
       foo_master_id int not null primary key
      ,current_foo_id int
)


create table foo_detail (
       foo_detail_id int not null primary key
       foo_master_id int not null
)

alter table foo_master
  add constraint fk_foo_current_detail
      foreign key (current_foo_id)
      references foo_detail

alter table foo_detail
  add constraint fk_foo_master
      foreign key (foo_master_id)
      references foo_master

레코드를 삭제하면 순환 의존관계로 인해 이러한 문제가 발생할 수 있습니다.

이를 위한 더 나은 스키마는 다음과 같습니다.

create table foo_master (
       foo_master_id int not null primary key
)


create table foo_detail (
       foo_detail_id int not null primary key
       foo_master_id int not null
       is_current char (1)
)

alter table foo_detail
  add constraint fk_foo_master
      foreign key (foo_master_id)
      references foo_master

이는 관계가 비순환적이며 '현재' foo_detail 레코드를 식별할 수 있음을 의미합니다.

에 최근 추가된 쿼리 구문 중 .NOCYCLE키워드 - 데이터 내의 순환 참조를 처리하기 위해 명시적으로 작성되었습니다.저는 전혀 문제될 것이 없고, 이전에 이런 종류의 모델을 다루어야 했습니다.특히 지연 가능한 제약 조건을 지원하는 Oracle에서는 이 작업이 그다지 어렵지 않습니다.

퍼포먼스상의 이유로 순환 레퍼런스가 행해지는 것을 본 적이 있습니다.외관상으로는 보기 흉하고 퍼포먼스는 무시할 수 있습니다.

예: 일부 게시판(PHPBB가 이것을 한다고 생각합니다)은 카테고리 테이블에 스레드 내의 마지막 투고에 대한 바로 가기인 lastpostid를 가지고 있습니다.

그러면 원이 생성됩니다.이 경우 마지막 게시물은 카테고리 테이블에 FK이고 카테고리 테이블은 마지막 게시물에 FK를 반환합니다.

말씀드렸듯이, 전 별로 좋아하지 않지만, 그렇게 하는 걸 본 적이 있어요.

순환 참조는 전염병처럼 피해야 한다.쌍방향 관계, 혹은 자기 자신과의 관계(테이블의 경우)를 설정할 수 있지만, 순환 의존은 단지 문제를 일으킬 뿐이다.

드물게 나는 필요한 1:1의 관계를 만나 순환적인 관계를 강요한다.

이러한 관계의 외부 키필드는 null이어야 합니다.그렇지 않으면 테이블에서 행을 삭제할 수 없습니다.

쓰기 전용 데이터베이스를 사용하는 경우에는 문제가 없을 것 같습니다.CRUD의 RUD 부분을 사용할 계획이라면 이러한 부분을 처리할 때 복잡한 문제가 발생할 수 있습니다(보통 피할 수 있는).

언급URL : https://stackoverflow.com/questions/1006917/are-circular-references-acceptable-in-database

반응형