Допустимы ли циклические ссылки в базе данных? - PullRequest
25 голосов
/ 17 июня 2009

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

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

Ответы [ 8 ]

23 голосов
/ 20 июля 2012

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

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';
13 голосов
/ 17 июня 2009

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

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

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

4 голосов
/ 18 июня 2009

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

3 голосов
/ 17 июня 2009

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

1 голос
/ 17 июня 2009

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

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

При этом создается круг, в котором последнее сообщение имеет FK для таблицы категорий, а таблица категорий - FK для последнего сообщения.

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

1 голос
/ 17 июня 2009

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

0 голосов
/ 17 июня 2009

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

0 голосов
/ 17 июня 2009

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

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

...