Допустимы ли циклические ссылки в базе данных?

когда циклические ссылки приемлемы в базе данных?

теоретическая и практическая, любая помощь приветствуется.

8 ответов


записи, которые указывают на другие записи, полезны в базе данных. Иногда эти записи образуют цикл. Это все еще может пригодиться. Единственное реальное раздражение на практике-это избегать нарушения ограничений.

например, если у вас есть таблица user и transaction, у пользователя может быть указатель на его последнюю транзакцию. Сначала вам нужно вставить транзакцию, а затем обновить last_transaction_id до правильного значения. Пока существуют обе эти записи, их нельзя стереть, потому что the user.last_transaction_id указывает на transaction.id и transaction.user_id указывает на user.id. Это означает, что пользователь без операции имеет значение null last_transaction_id. Это также означает, что вы должны обнулить это поле перед удалением транзакции.

управление этими ограничениями внешнего ключа-это боль, но это, безусловно, возможно. Могут возникнуть проблемы при добавлении ограничений в базу данных позже, которые вводят новые циклические зависимости. Вы должны быть осторожны в этой ситуации. Однако, пока поскольку одна из записей цикла имеет поле внешнего ключа с нулевым значением, цикл можно разбить и удалить записи. Обновления обычно не являются проблемой, пока вы вставляете записи в правильном порядке.


рассмотрим города и Штаты. Каждый город существует внутри государства. В каждом штате есть столица.

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

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

первая проблема - вы не можете создать эти таблицы, как показано. Решение создать их без внешних ключей, а затем добавить внешние ключи.

вторая проблема-вы не можете вставлять строки в любую таблицу, так как для каждой вставки потребуется уже существующая строка в другой таблице. Решение состоит в том, чтобы установить один из столбцов внешнего ключа равным NULL, и вставьте эти данные в два этапа. например,

INSERT INTO city (city, state) VALUES ('Miami', NULL);
INSERT INTO state (state, capital_city) VALUES ('Florida', 'Miami');
UPDATE city SET state='Florida' WHERE city='Miami';

это технически возможно сделать, но это может вызвать всевозможные проблемы при удалении записей, поскольку это создает проблемы с курицей и яйцом. Эти проблемы часто принимают решительные меры, такие как ручное удаление 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

затем удаление записи может вызвать такую проблему с курицей и agg из-за круговых зависимостей.

лучшая схема для этого выглядит например:

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 все еще может быть идентифицирована.


одно из последних дополнений к синтаксису иерархического запроса Oracle -NOCYCLE ключевое слово-было сделано специально для этой цели-для работы с круговыми ссылками в данных. Я не вижу в этом ничего плохого, и мне приходилось иметь дело с такой моделью раньше. Это не слишком сложно, особенно в Oracle, который поддерживает отложенные ограничения.


циклических ссылок следует избегать, как чумы. Можно установить двухсторонние отношения или даже отношения с самим собой (если вы были таблицей), но циклическая зависимость просто напрашивается на неприятности.


Я видел круговые ссылки, сделанные по соображениям производительности. Это выглядит уродливо, хотя, и производительность может быть незначительной.

пример: некоторые доски объявлений (я думаю, что phpBB делает это) имеют lastpostid в таблице категорий, которая является ярлыком для последнего сообщения в потоке.

Это создает круг, где последний пост имеет FK в таблицу категорий, а таблица категорий имеет FK обратно к последнему сообщению.

Как я уже сказал, мне не очень нравится но я видел, как это делается.


редко я сталкиваюсь с отношением 1:1, которое необходимо и накладывает круговое отношение

обратите внимание, что поля внешнего ключа в такой связи должны быть nullable, иначе вы никогда не сможете удалить строки из таблиц


Я думаю, это не проблема, если вы используете оставить только базу. Если вы планируете использовать часть RUD CRUD, вы, вероятно, столкнетесь с (обычно предотвратимыми) сложными проблемами при их решении.