Основы моделирования и базы данных

Базовые принципы проектирования. Часть 4

В лекции последовательно разбирается преобразование одной плоской таблицы с данными об автомобилях в хорошо структурированную реляционную модель. Логика построена от выявления проблем избыточности и жёсткости схемы до их разрешения: кодирование текстовых атрибутов справочниками, введение ассоциативных таблиц для связей «многие-ко-многим», разделение статических и динамических данных с выделением истории цен. Итогом становится набор из десяти таблиц, свободных от аномалий вставки и обновления, и вводится понятие нормализации как основы грамотного проектирования баз данных.

Основные мысли

В результате изучения лекции слушатель будет способен:
1. Объяснять недостатки хранения перечислимых атрибутов в виде текстового поля и решения с добавлением столбцов под каждое значение.
2. Проектировать справочные таблицы для замены повторяющихся текстовых значений компактными кодами.
3. Строить ассоциативные таблицы для корректной реализации связей «многие-ко-многим» между сущностями.
4. Разделять статические и изменяющиеся во времени атрибуты, вынося динамические данные в отдельную таблицу с историей.
5. Оценивать уровень избыточности в структуре данных и обосновывать необходимость нормализации.
6. Преобразовывать исходную ненормализованную таблицу в совокупность взаимосвязанных таблиц, лишённых аномалий обновления, вставки и удаления.
7. Применять внешние ключи для связывания таблиц и обеспечения ссылочной целостности.
8. Понимать роль языка SQL в извлечении данных из нормализованной структуры и представлении их в удобном для пользователя виде.
Показывать лекцию целиком
Краткое изложение
Введение
Мы решаем задачу превращения текстовой комплектации автомобиля в кодированное представление, пригодное для быстрого поиска. Исходная таблица содержит столбцы: модель, привод, комплектация (текстовая строка с перечислением опций), цвет, коробка передач, цена и дата. Уникальность автомобиля сначала определяется парой «модель–привод».

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

Недостатки подхода
Кардинальный недостаток — появление новой опции (например, разъёма AUX или устройства быстрой зарядки) требует добавления нового столбца в существующую таблицу. На уровне базы данных это критичная операция: она затрагивает файловую структуру хранения, вынуждает массово проставлять значения (чаще всего нули) во всех ранее созданных строках и может приводить к ошибкам в существующих запросах, которые обязаны заранее знать полный перечень столбцов. Кроме того, для столбцов, разрешающих неопределённые значения, вступают в силу особенности NULL значения, отличающегося от пустой строки и требующего аккуратной обработки в условиях и агрегациях. Всё это делает схему нестабильной и плохо расширяемой.

Справочник элементов комплектации
Альтернатива, укладывающаяся в плоскую табличную модель, — перенести элементы комплектации в строки. Создаётся таблица-справочник Комплектация (ID, название). В ней перечисляются все возможные опции: люк, климат контроль, навигатор, кожаный салон и так далее. При появлении нового элемента достаточно вставить одну строку — никаких изменений схемы, никаких массовых обновлений старых записей.

Ассоциативная таблица «Модель–Привод–Комплектация»
Теперь нужно связать автомобили с элементами комплектации. Уникальность автомобиля расширяется до тройки «модель–привод–комплектация». Связь «многие-ко-многим» организуется через ассоциативную таблицу — она содержит столбцы: идентификатор пары «модель–привод» (внешний ключ, FK) и идентификатор элемента комплектации (FK). Если автомобиль имеет люк и климат-контроль, в таблице появятся две строки с одним и тем же автомобилем, но разными элементами. Такой принцип повторяет уже знакомый подход с моделью и приводом.

Учёт нескольких комплектаций для одного автомобиля
У одной пары «модель–привод» может быть несколько вариантов комплектации. Чтобы различать их, в ассоциативную таблицу добавляется столбец Номер комплектации. Теперь каждая комплектация конкретного автомобиля получает свой порядковый номер (1, 2, 3…). Выбрав все строки с одинаковыми ключом автомобиля и номером комплектации, получаем полный список опций именно этого варианта. Номера комплектаций могут повторяться у разных автомобилей — контекст задаётся внешним ключом автомобиля.

Понятие нормализации
Весь проделанный путь — удаление избыточности, разделение сущностей, создание справочников и ассоциативных связей — называется нормализацией. Это процесс проектирования структуры базы данных, устраняющий противоречивость и аномалии манипуляции данными. Мы на практике осуществили нормализацию исходной таблицы, шаг за шагом повышая её уровень.

Проблема цены и даты
Дата в базах данных поддерживается специальными типами DATE или DATETIME (а также Unix форматом), оптимизированными для поиска и не требующими кодирования. Цена — числовое значение, тоже не нуждающееся в кодировании. Однако хранение цены и даты в основной таблице ведёт к избыточности: при каждом изменении цены приходится дублировать всю строку с неизменными характеристиками автомобиля (цвет, коробка передач, комплектация). Это порождает аномалии обновления и раздувает объём.

Таблица истории цен
Решение — вынести динамические атрибуты в отдельную таблицу Цена (ID, СписокFK, Дата, Цена). Здесь СписокFK — внешний ключ, указывающий на уникальный идентификатор автомобиля со всеми его статическими параметрами, полученный после предыдущих шагов нормализации. Каждая запись фиксирует цену на определённую дату. При изменении цены просто добавляется новая строка с новой датой и значением, а старые записи сохраняются, формируя историю. Исходная таблица автомобилей освобождается от столбцов цены и даты, храня только статическую информацию и ссылки.

Результат: из одной таблицы — десять
В результате преобразований мы получили примерно десять таблиц вместо одной:
• справочники цветов, коробок передач, моделей, приводов, элементов комплектации;
• ассоциативная таблица «Модель–Привод» (кодирует уникальные автомобили);
• ассоциативная таблица «Модель–Привод–Комплектация» с номером комплектации;
• основная таблица автомобилей со ссылками на справочники;
• таблица истории цен.
Все текстовые поля заменены числовыми кодами (внешними ключами), что ускоряет поиск, уменьшает объём хранимых данных и исключает аномалии вставки, обновления и удаления.

Заключение и роль SQL
Множество связанных таблиц кажется сложным для человека, но для выдачи итоговой плоской выборки существует язык SQL (Structured Query Language — язык структурированных запросов). SQL позволяет соединять таблицы, подменять коды осмысленными названиями и представлять данные в том же виде, с которого мы начинали. Хранение же в нормализованной форме гарантирует целостность, непротиворечивость и эффективность. В дальнейшем мы научимся проектировать базы данных по техническому заданию и бизнес-процессам, а также формулировать сложные SQL запросы, например, для расчёта средней стоимости автомобилей с люком.

Краткие итоги

Проектирование надёжного хранилища данных начинается с критического анализа одной «плоской» таблицы, куда часто пытаются уместить всё сразу. На первый взгляд такое представление интуитивно понятно, но оно быстро порождает взрывную избыточность и блокирует развитие системы. Практический разбор примера с автомобилями демонстрирует универсальный алгоритм наведения порядка.

Исходная структура с текстовым полем комплектации и дублирующимися описаниями сталкивается с первой трудностью: поиск по отдельным опциям крайне неэффективен, а добавление новой опции требует перестройки всей схемы, если избрать путь «отдельный столбец на каждый признак». Это не просто замедляет работу, но и ставит под удар целостность данных при каждом изменении модели предметной области.

Выход находится в переводе мышления от «горизонтального» расширения таблицы к «вертикальному» — размещению изменчивых сущностей в строках специализированных справочников. Так рождается каталог элементов комплектации, пополнение которого перестаёт быть критическим событием. Следующий шаг — моделирование реальных бизнес связей. Отношение «многие-ко-многим» между автомобилями и опциями формализуется ассоциативной таблицей, а введение номера комплектации элегантно разрешает коллизию нескольких вариантов оснащения для одного автомобиля без дублирования его неизменных характеристик.

Параллельно вскрывается проблема смешения статического «скелета» объекта и его динамических атрибутов, таких как цена с привязкой ко времени. Хранение цены и даты непосредственно в карточке товара вынуждает тиражировать константную информацию при каждом ценовом колебании, что является классической аномалией обновления. Выделение самостоятельной таблицы истории цен с внешним ключом на статический объект решает эту задачу: каждое изменение фиксируется новой строкой, сохраняя хронологию и устраняя избыточность.

Все перечисленные действия — выделение справочников, создание ассоциативных связей, разделение статики и динамики — составляют суть нормализации. Её ценность не в формальном следовании правилам, а в практическом результате: получается структура, готовая к расширению, быстрому поиску и свободная от противоречий. Внешняя сложность десятка таблиц снимается языком SQL, который собирает данные обратно в удобную для человека форму. Таким образом, грамотное проектирование не усложняет, а упрощает жизнь и разработчику, и конечному пользователю, закладывая фундамент для долгосрочной эксплуатации информационной системы.
Исходная задача и проблемы плоской таблицы
Данные о продажах автомобилей хранятся в одной таблице с полями: модель, привод, комплектация (текстовое перечисление опций), цвет, коробка передач, цена, дата. Поиск по отдельной опции, например «люк», требует сканирования текстового поля и работает медленно. Первое решение — создать для каждой возможной опции свой столбец и проставлять 1 или 0.

Недостатки столбцового подхода
Главный недостаток — при добавлении новой опции необходимо добавить столбец, что в реляционной базе данных является ресурсоёмкой и рискованной операцией. Требуется массовое обновление старых строк, и схема становится нестабильной. Кроме того, работа с NULL-значениями (отсутствием данных) усложняет запросы.

Справочник элементов комплектации
Более гибкое решение — хранить перечень опций не в столбцах, а в строках отдельной таблицы-справочника «Комплектация» (ID, название). Появление новой опции означает лишь добавление строки, схема таблицы не меняется.

Ассоциативная таблица для связи «многие-ко-многим»
Уникальность автомобиля теперь описывается тройкой «модель–привод–комплектация». Связь автомобиля с опциями организуется через ассоциативную таблицу «Модель–Привод–Комплектация» (ID, ID_модели_привода (FK), ID_комплектации (FK)). Каждая опция автомобиля представлена отдельной строкой.

Учёт нескольких вариантов комплектации
Один автомобиль может иметь несколько комплектаций. Для их разделения в ассоциативную таблицу добавляется поле «Номер комплектации». Теперь все опции группируются по паре (ID_автомобиля, номер_комплектации). Это позволяет хранить любое число вариантов без дублирования.

Понятие нормализации
Описанный процесс удаления избыточности и разбиения данных на взаимосвязанные таблицы называется нормализацией. Она устраняет аномалии вставки, обновления и удаления.

Проблема цены и даты
Цена и дата — динамические атрибуты. Если хранить их непосредственно в таблице автомобиля, при каждом изменении цены приходится дублировать всю строку со статическими характеристиками (цвет, коробка передач). Это порождает избыточность.

Таблица истории цен
Выход — вынести цену и дату в отдельную таблицу «Цена» (ID, СписокFK, Дата, Цена). СписокFK — внешний ключ, указывающий на уникальный идентификатор автомобиля со всеми статическими атрибутами. Каждое изменение цены добавляет новую строку с актуальной датой, сохраняя историю.

Итоговая структура
Из одной таблицы получается около десяти:
• справочники цветов, коробок передач, моделей, приводов, элементов комплектации;
• ассоциативная таблица «Модель–Привод»;
• ассоциативная таблица «Модель–Привод–Комплектация» с номером комплектации;
• таблица автомобилей со ссылками на справочники;
• таблица истории цен.
Все текстовые значения заменены числовыми внешними ключами, что ускоряет поиск и экономит память.

Роль SQL
Язык SQL (Structured Query Language) позволяет соединять (JOIN) все эти таблицы, заменять коды названиями и формировать для пользователя точно такую же плоскую выборку, как исходная таблица. Нормализованное хранение при этом гарантирует целостность и эффективность. Дальнейшее обучение будет посвящено осознанному проектированию баз данных и написанию SQL-запросов для сложных аналитических вопросов, например, расчёта средней стоимости автомобилей с определённой опцией.

Выводы

1. Хранение перечислимых атрибутов в виде текстового поля делает невозможным быстрый поиск по отдельным элементам без сканирования строк.
2. Добавление столбца под каждую новую опцию приводит к нестабильности схемы и массовым обновлениям исторических данных.
3. Справочные таблицы позволяют расширять перечень допустимых значений простым добавлением строк, не меняя структуры хранения.
4. Связи «многие-ко-многим» реализуются ассоциативной таблицей, хранящей пары внешних ключей.
5. Введение порядкового номера комплектации в ассоциативную таблицу позволяет хранить несколько вариантов опций для одной сущности.
6. Нормализация — это последовательный процесс устранения избыточности и аномалий в структуре таблиц.
7. Статические и динамические атрибуты сущности должны быть разделены на разные таблицы во избежание дублирования.
8. Историю изменения цен корректно хранить в отдельной таблице с датой, ссылающейся на статическую запись товара.
9. Замена текстовых значений числовыми внешними ключами ускоряет выполнение запросов и экономит дисковое пространство.
10. SQL запросы позволяют «склеивать» множество нормализованных таблиц и возвращать данные в привычной плоской форме.
11. Хорошо спроектированная база данных исключает противоречивость информации и аномалии вставки, обновления и удаления.
12. Принципы нормализации универсальны и применимы к любой предметной области, где требуется надёжное хранение данных.

Вопросы для самопроверки

1. Почему текстовое поле с перечислением опций комплектации неудобно для поиска автомобилей по конкретной опции?
2. Какие риски влечёт добавление нового столбца в существующую таблицу при появлении очередного элемента комплектации?
3. Чем NULL-значение принципиально отличается от пустой строки и почему это важно при обновлении столбца?
4. Зачем создавать справочник элементов комплектации, если можно сразу заносить названия в ассоциативную таблицу?
5. Как ассоциативная таблица позволяет реализовать связь «многие-ко-многим» между автомобилем и опциями?
6. Для чего в таблицу «Модель–Привод–Комплектация» добавлен номер комплектации?
7. Почему номера комплектаций могут повторяться у разных автомобилей и не вызывают путаницы?
8. Что такое нормализация и какую главную цель она преследует?
9. В чём заключается избыточность при хранении цены и даты непосредственно в таблице автомобилей?
10. Как выделение таблицы истории цен решает проблему аномалий обновления?
11. Каким образом SQL позволяет пользователю видеть данные в виде одной плоской таблицы, несмотря на нормализованное хранение?
12. Перечислите основные типы таблиц, появившиеся в результате нормализации исходной структуры (справочники, ассоциативные, основная, историческая).
Вернуться к учебному плану