Сущности, атрибуты и связи

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

ER-модель (Entity-Relationship, «сущность-связь») — это способ описать структуру предметной области в терминах сущностей, их атрибутов и связей между ними, не привязываясь к конкретной СУБД. Предложена Питером Ченом в 1976 году.

Зачем нужна ER-модель

Реляционная схема (таблицы, ключи) — это уже технический артефакт. Но прежде чем её строить, нужно понять саму предметную область: что в магазине вообще есть и как это связано. Если сразу прыгнуть к таблицам, легко упустить связь или продублировать сущность. ER-модель — это промежуточный, человекопонятный язык между заказчиком и базой данных. На ней проще обсуждать: «у заказа есть клиент», «книгу написали авторы» — и лишь затем механически перевести это в таблицы (следующий урок).

Три уровня проектирования

Прежде чем нырять в детали, поместим ER-моделирование на карту проектирования. Принято выделять три уровня моделей. Концептуальная модель (наш случай) — высокоуровневое описание предметной области без оглядки на конкретную СУБД: сущности, связи, бизнес-правила. Логическая модель — перевод концептуальной в конкретную модель данных (для нас — реляционную): таблицы, столбцы, ключи, но ещё без физических деталей. Физическая модель — как это ляжет в конкретную СУБД: типы данных, индексы, разбиение. ER-диаграмма живёт на концептуальном уровне; следующий урок — переход к логической модели; физику мы затронем в разделе про хранение. Такое разделение перекликается с трёхуровневой архитектурой из первого раздела и преследует ту же цель: думать о смысле данных отдельно от их реализации, чтобы решения на одном уровне не диктовались деталями другого.

Сущности

Сущность (entity) — объект предметной области, о котором мы храним данные и который можно отличить от других. Тип сущности — это класс однотипных объектов (Клиент, Книга, Заказ), а экземпляр сущности — конкретный объект (клиент «Анна»). На ER-диаграмме тип сущности рисуют прямоугольником. В будущей реляционной схеме типу сущности обычно соответствует таблица, а экземпляру — строка.

Как отличить сущность от атрибута? Сущность — это то, о чём мы хотим хранить несколько фактов и что имеет самостоятельное существование. «Клиент» — сущность (у него есть имя, телефон, заказы). «Цвет» — скорее атрибут товара, а не отдельная сущность, если про цвет нам нечего больше сказать.

Как читать ER-диаграмму

Хотя в текстовом курсе мы не рисуем диаграммы, важно знать их условные обозначения, потому что вы встретите их везде. В классической нотации Чена прямоугольник — тип сущности, овал — атрибут, ромб — связь, а линии соединяют их. Двойные контуры означают «слабые» элементы (слабая сущность, идентифицирующая связь — об этом в третьем уроке). Кардинальность подписывают у линий: «1» и «N» либо специальными значками. Существует и более компактная нотация «вороньей лапки» (crow's foot), популярная в инструментах проектирования, где множественность изображается раздвоенным окончанием линии. Какую бы нотацию вы ни встретили, за значками стоят те же три понятия — сущность, атрибут, связь, — поэтому, освоив словарь, вы прочтёте любую диаграмму.

Атрибуты и их виды

Атрибут — свойство сущности. Атрибуты бывают разных видов, и различать их полезно, потому что на этапе перевода в таблицы они ведут себя по-разному.

  • Простой (атомарный) — неделим: age, cena.
  • Составной — состоит из частей: address = (город, улица, дом). Его либо хранят целиком, либо разбивают на отдельные столбцы.
  • Многозначный — у одного экземпляра несколько значений: у клиента несколько телефонов. Многозначный атрибут нельзя положить в одну ячейку (нарушит 1NF) — его выносят в отдельную таблицу.
  • Производный (вычислимый) — выводится из других: age из birth_date. Его обычно не хранят, а вычисляют.
  • Ключевой — однозначно идентифицирует экземпляр (будущий первичный ключ).

Связи

Связь (relationship) — ассоциация между сущностями. «Клиент оформляет Заказ», «Автор пишет Книгу». На диаграмме связь традиционно рисуют ромбом. У связи может быть своя степень — число участвующих типов сущностей: бинарная (два типа, самый частый случай), тернарная (три) и так далее.

У связи бывают и собственные атрибуты. Классический пример — связь «Студент изучает Курс» с атрибутом ocenka: оценка принадлежит не студенту и не курсу по отдельности, а именно факту изучения. Такие атрибуты подсказывают, что связь при переводе в таблицы станет отдельной таблицей.

Сущность или атрибут: как решить

Граница между сущностью и атрибутом — одно из самых частых мест сомнений в проектировании, и стоит дать практический критерий. Спросите про кандидата три вещи. Есть ли у него собственные свойства, которые мы хотим хранить? Если «город» — это только название, он атрибут клиента; если про город мы храним регион, население, индекс — он тянет на сущность. Существует ли он независимо и переиспользуется? Если на «город» ссылаются многие клиенты и мы не хотим дублировать его данные — это сущность со своей таблицей. Бывает ли его несколько у одного владельца? Тогда это как минимум многозначный атрибут, а скорее отдельная сущность. Эти вопросы переводят интуицию в проверяемые критерии. Ошибиться в обе стороны легко: сделать сущностью то, что было простым атрибутом (лишние таблицы и соединения), или, наоборот, спрятать в атрибут то, у чего есть своя жизнь (избыточность и потеря данных).

Виды связей по кардинальности

Кардинальность описывает, сколько экземпляров одной сущности может быть связано с экземпляром другой. Три базовых типа:

ТипОбозначениеПример
Один-к-одному1:1Сотрудник — его пропуск
Один-ко-многим1:NКлиент — его заказы
Многие-ко-многимM:NКнига — авторы (у книги много авторов, у автора много книг)

Кардинальность — ключевое решение проектирования. Перепутав 1:N и M:N, вы построите неверную схему. Спросите себя про обе стороны: «у одного клиента сколько заказов?» (много) и «у одного заказа сколько клиентов?» (один) — значит, связь 1:N.

Степень связи: бинарные, тернарные, рекурсивные

Большинство связей бинарны (соединяют два типа сущностей), но не все. Рекурсивная связь соединяет тип сущности с самим собой: «сотрудник руководит сотрудником», «деталь входит в состав детали». Такие связи естественны для иерархий и реализуются самоссылающимся внешним ключом, как мы видели в разделе про ключи. Тернарная связь соединяет сразу три сущности, когда факт по-настоящему трёхсторонний: «поставщик поставляет товар в магазин» — здесь ни одна пара не передаёт смысл без третьего участника. Тернарные связи коварны: их часто ошибочно разбивают на три бинарные, теряя информацию (из трёх отдельных связей «кто-что», «что-где», «кто-где» нельзя восстановить, какой именно поставщик привёз какой товар в какой магазин). Признак истинной тернарной связи — наличие атрибута, зависящего от всех трёх участников сразу (например, количество поставки). Такие связи при переводе становятся таблицей с тремя внешними ключами.

Класс принадлежности (обязательность)

Помимо «сколько», важно «обязательно ли». Класс принадлежности (участие в связи) бывает обязательным (total) или необязательным (partial). «Каждый заказ обязан принадлежать клиенту» — обязательное участие заказа. «Не у каждого клиента есть заказы» — необязательное участие клиента. Это влияет на то, разрешим ли мы NULL во внешнем ключе и нужны ли внешние соединения при выборках.

Пример: ER-описание интернет-магазина

Соберём словами небольшую ER-модель.

  • Сущности: Клиент(id, имя, email, телефон), Заказ(номер, дата), Товар(артикул, название, цена).
  • Связь «Клиент оформляет Заказ» — 1:N (у клиента много заказов, у заказа один клиент). Участие заказа обязательное.
  • Связь «Заказ содержит Товар» — M:N (в заказе много товаров, товар в разных заказах). У связи есть атрибут quantity (количество).
  • Телефон клиента — потенциально многозначный (несколько номеров), email — простой атрибут, адрес — составной.

Уже на этом уровне видны будущие решения: M:N-связь и многозначный телефон превратятся в отдельные таблицы. Но пока мы говорим о предметной области, а не о таблицах — и это правильно.

Типичные ошибки проектирования

  • Сущность вместо атрибута и наоборот. Делать «Цвет» отдельной сущностью без причины — переусложнение; хранить несколько телефонов в одном атрибуте — потеря данных.
  • Неверная кардинальность. Принять M:N за 1:N — и часть связей потеряется; всегда проверяйте обе стороны.
  • Атрибут связи приписан сущности. Оценку за курс кладут в студента или в курс, хотя она принадлежит факту «студент изучает курс».
  • Игнорирование обязательности. Не продумали участие — и в схеме оказываются заказы без клиента.

Итог

  • ER-модель описывает предметную область сущностями, атрибутами и связями — до построения таблиц.
  • Атрибуты бывают простыми, составными, многозначными, производными и ключевыми; вид влияет на будущую схему.
  • Кардинальность (1:1, 1:N, M:N) и обязательность участия — ключевые решения проектирования.
  • Атрибуты связи (например, оценка или количество) принадлежат самой связи, а не сущностям.
Проверьте себя
1. Какому виду связи соответствует «у книги может быть несколько авторов, а автор пишет несколько книг»?
AОдин-к-одному (1:1)
BОдин-ко-многим (1:N)
CМногие-ко-многим (M:N)
DЭто не связь, а атрибут
2. Куда правильно отнести атрибут «оценка» в связи «Студент изучает Курс»?
AК сущности Студент
BК сущности Курс
CК самой связи «изучает»
DЭто производный атрибут, его не хранят
3. Что такое многозначный атрибут?
AАтрибут с очень большим значением
BАтрибут, у которого один экземпляр сущности может иметь несколько значений
CВычисляемый атрибут
DАтрибут из нескольких частей
Поддержать проект