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