После декомпозиции отношения на две таблицы соединение возвращает лишние комбинации: какой критерий показыв...

После декомпозиции отношения на две таблицы соединение возвращает лишние комбинации: какой критерий показывает, что декомпозиция была без потерь?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Декомпозиция отношения на два отношения является без потерь, если их естественное соединение всегда восстанавливает исходное отношение без добавления ложных кортежей и без потери исходных кортежей. Для декомпозиции на схемы R1 и R2 общий набор атрибутов должен функционально определять все атрибуты хотя бы одной из частей — это проверяется относительно заданных функциональных зависимостей.

Исторический контекст

Декомпозиция возникла как средство нормализации реляционной схемы. Разделение одной таблицы уменьшает дублирование данных и риск аномалий вставки, обновления и удаления.

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

Постановка проблемы

Пусть отношение содержит атрибуты A, B и C, а его разбиение создаёт отношения R1(A, B) и R2(A, C). Если одно значение A связано с несколькими значениями B и несколькими значениями C независимо, соединение R1 и R2 образует все комбинации этих значений.

В результате появляются строки, которых в исходном отношении не было. Такая ошибка особенно опасна, если результат соединения используется для отчётов, расчёта показателей или формирования зависимых записей.

Подробное решение

Для двух отношений R1 и R2 с пересечением X декомпозиция гарантированно является без потерь, если функциональные зависимости подразумевают хотя бы одно из условий:

  • X функционально определяет все атрибуты R1;
  • X функционально определяет все атрибуты R2.

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

Например, исходные факты могут выглядеть так: для A=1 существуют пары B=x, C=p и B=y, C=q. После разбиения в R1 останутся пары (1,x) и (1,y), а в R2 — (1,p) и (1,q). Соединение по A дополнительно создаст (1,x,q) и (1,y,p).

Минимальная иллюстрация:

WITH r(a, b, c) AS ( VALUES (1, 'x', 'p'), (1, 'y', 'q') ), r1 AS ( SELECT DISTINCT a, b FROM r ), r2 AS ( SELECT DISTINCT a, c FROM r ) SELECT r1.a, r1.b, r2.c FROM r1 JOIN r2 ON r2.a = r1.a;

Запрос вернёт четыре комбинации, хотя в исходном отношении было только две. Причина не в ошибке оператора соединения, а в том, что атрибут A не определяет ни B, ни C.

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

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

Ситуация из практики

В системе курсов была таблица с атрибутами Курс, Преподаватель и Аудитория. Её разделили на связи «курс—преподаватель» и «курс—аудитория», предполагая, что курс однозначно определяет оба значения.

Первый вариант оставлял разбиение как есть. Он был простым, но неверным: если у курса несколько преподавателей и аудиторий, соединение создавало пары каждого преподавателя с каждой аудиторией.

Второй вариант добавлял в ключ конкретного занятия: Курс, Дата и Время. Это устраняло неоднозначность, но требовало изменить модель и мигрировать данные.

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

Что кандидаты часто упускают

  1. Достаточно ли того, что общий атрибут является первичным ключом одной из таблиц?

Да, если этот общий атрибут действительно является ключом одной из декомпозированных таблиц и ограничения гарантируют соответствующую функциональную зависимость. Например, если общий атрибут X — первичный ключ R1, то X функционально определяет все атрибуты R1, что обеспечивает условие без потерь для этой части.

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

  1. Может ли конкретный набор данных иметь декомпозицию без потерь, хотя общего функционального ограничения нет?

Да. В текущем экземпляре отношения значения могут случайно не порождать ложных комбинаций. Например, у каждого значения общего атрибута может встретиться только одна комбинация, даже если схема не запрещает несколько комбинаций в будущем.

Для гарантии на уровне схемы этого недостаточно: при появлении новых данных соединение может стать lossy. Поэтому проверяют зависимости, действующие для всех допустимых экземпляров отношения.

  1. Почему внешний ключ сам по себе не гарантирует декомпозицию без потерь?

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

Например, несколько строк дочерней таблицы могут ссылаться на одного родителя. Соединение при этом корректно связывает строки, но при неверно выбранной декомпозиции всё равно может породить лишние комбинации между независимыми дочерними фактами.