Вопрос схемы базы данных - PullRequest
5 голосов
/ 16 июня 2010

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

Итак 4 таблицы: Страна, Штат, Город, Район.

Реальные отношения в жизни: Страна владеет несколькими штатами, которые владеют несколькими городами, имеющими несколько кварталов.

В модели данных: связываем ли мы их с FK одинаково или связываем каждый с каждым? Как и в каждой таблице, будет даже идентификатор страны, идентификатор штата, CityID и NeighbourhoodID, так что каждый связан с каждым? В противном случае, чтобы достичь соседства со страной, нам нужно присоединиться к двум другим столам между ними?

Есть еще таблицы, которые мне нужно вести для IP-адреса городов, широты / долготы и т. Д.

1 Ответ

5 голосов
/ 16 июня 2010

Наиболее близким к отраслевому стандарту является следующее: каждая зависимая таблица связана внешним ключом со своим непосредственным родителем:

create table country
(country_id number not null
 , country_name varchar2(30)
 , constraint country_pk primary key (country_id)
 )
/
create table state
(state_id number not null 
 , state_name varchar2(30)
 , country_id number not null
 , constraint state_pk primary key (state_id)
 , constraint state_country_fk foreign key (country_id)
        references country(country_id)
 )
/
create table city
(city_id number not null 
 , city_name varchar2(30)
 , state_id number not null 
 , constraint city_pk primary key (city_id)
 , constraint city_state_fk foreign key (state_id)
        references state(state_id)
 )
/
create table neighbourhood
(neighbourhood_id number not null 
 , neighbourhood_name varchar2(30)
 , city_id number not null 
 , constraint neighbourhood_pk primary key (neighbourhood_id)
 , constraint neighbourhood_city_fk foreign key (city_id)
        references city(city_id)
 )
/

Альтернативный подход, который в значительной степени потерял популярность, заключается в определении первичных ключей дочерних таблиц как составных ключей, включая ключи непосредственной родительской таблицы:

create table state
(country_id number not null
 , state_id number not null 
 , state_name varchar2(30)
 , constraint state_pk primary key (country_id, state_id)
 , constraint state_country_fk foreign key (country_id)
        references country(country_id)
 )
/
create table city
(country_id number not null
 , state_id number not null 
 , city_id number not null 
 , city_name varchar2(30)
 , constraint city_pk primary key (country_id, state_id, city_id)
 , constraint city_state_fk foreign key (country_id, state_id)
        references state(country_id, state_id)
 )
/
create table neighbourhood
(country_id number not null
 , state_id number not null 
 , city_id number not null 
 , neighbourhood_id number not null 
 , neighbourhood_name varchar2(30)
 , constraint neighbourhood_pk primary key (country_id, state_id, city_id, neighbourhood_id)
 , constraint neighbourhood_city_fk foreign key (country_id, state_id, city_id)
        references city(country_id, state_id, city_id)
 )
/

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

Ваше предложение является альтернативной версией этого:

create table state
(state_id number not null 
 , state_name varchar2(30)
 , country_id number not null
 , constraint state_pk primary key (state_id)
 , constraint state_country_fk foreign key (country_id)
        references country(country_id)
 )
/
create table city
(city_id number not null 
 , city_name varchar2(30)
 , country_id number not null
 , state_id number not null 
 , constraint city_pk primary key (city_id)
 , constraint city_country_fk foreign key (country_id)
        references country(country_id)
 , constraint city_state_fk foreign key (state_id)
        references state(state_id)
 )
/
create table neighbourhood
(neighbourhood_id number not null 
 , neighbourhood_name varchar2(30)
 , country_id number not null
 , state_id number not null 
 , city_id number not null 
 , constraint neighbourhood_pk primary key (neighbourhood_id)
 , constraint neighbourhood_country_fk foreign key (country_id)
        references country(country_id)
 , constraint neighbourhood_state_fk foreign key (state_id)
        references state(state_id)
 , constraint neighbourhood_city_fk foreign key (city_id)
        references city(city_id)
 )
/

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

С положительной стороны, как вы указываете, это может быть очень полезно для выполнения запросов, которые хотят вернуть Соседства для данной страны. Я работал над одной системой, где это было полезно (фактически она использовала унаследованные составные ключи, но принцип тот же). Однако это было очень специализированное хранилище данных, и даже тогда запросы, которые я выполнял, были запросами администратора / разработчика, а не приложениями. Если вы не имеете дело с огромными объемами данных (миллионы окрестностей), я думаю, что выигрыш в производительности от пропуска пары соединений не будет стоить дополнительных затрат на управление этими дополнительными столбцами.

Короче говоря, используйте первый подход: он аккуратный и стандартный.

редактировать

"Государство должно быть необязательным, поскольку не во всех странах есть государство. Затем Страна свяжется с городом непосредственно. "

Если это правда, это все меняет. Очевидно, что STATE не может использоваться в качестве идентифицирующего внешнего ключа для CITY. Поэтому CITY должен ссылаться на СТРАНУ. STATE может быть опциональным поиском по CITY.

Хотя я думаю, что в большинстве стран есть некоторые эквивалентные подразделения, такие как графства или департаменты. Даже такие микросостояния, как Лихтенштейн и Сан-Марино, имеют муниципалитеты (в Монако есть только один). Возможно, единственная нация, которая не является Ватиканом. Поэтому тщательно продумайте, следует ли структурировать вашу модель данных для поддержки одного или двух крайних случаев, или разбирать данные, вводя искусственное «Государство» для исключений, таких как Святой Престол. Ни один из подходов не является полностью удовлетворительным.

"все эти поля будут автозаполнение полей, поэтому не уверен, если который изменяет структуру таблицы в в любом случае? "

Не имеет значения.

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

Да, но опять же, вы не можете. В XP есть мощный принцип под названием YAGNI - он вам не понадобится . По сути, не делайте много работы и не усложняйте свой дизайн ради какого-то предполагаемого будущего требования, которое может никогда не прийти.

И если он все же наступит, то первым решением будет объединить NEIGHBORHOOD и СТРАНУ через промежуточные таблицы (или таблицы, если вы не используете STATE в качестве ссылки для CITY). Только если производительность этого запроса будет плохой! и оно упорно сопротивляется настройки вы должны рассмотреть настройки модели данных.

...