Теория реляционных баз данных: нормализация, отношения и объединения

Коротко о важном.

Нормализация БД

Первая нормальная форма (1НФ)

  • отсутствуют повторяющиеся группы данных
  • гарантируется элементарности(atomicity) данных (все данные являются автономными и независимыми).

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

Вторая нормальная форма (2НФ)

  • таблица удовлетворяет условиям 1НФ
  • каждый столбец зависит от всего ключа, а не от его части.

Третья нормальная форма (3НФ)

  • таблица удовлетворяет условиям 2НФ
  • ни один столбец не зависит от столбца, который не является частью первичного ключа
  • не содержит производных данных

 

Другие нормальные формы, не имеющие особой практической ценности:

Нормальная форма Бойса-Кодда(Boyce-Codd)

Вариант 3НФ. Предназначена для решения ситуации с наличием множества перекрывающихся ключей-кандидатов. По сути, не находит логического обоснования за пределами академического сообщества.

Четвертая нормальная форма

Предназначена для решения вопроса с многозначными зависимостями. Такие ситуации возникают, если в приведенной к 3НФ таблице один столбец составного первичного ключа зависит от другого столбца первичного ключа.

Пятая нормальная форма

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

Шестая нормальная форма (нормальная форма доменного ключа)

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

 

Отношения.

Однажды я услышал от женщин, что мужчины
немедленно стараются покинуть помещение, в котором
прозвучало слово "отношения". ...> ключом к успеху
отношений является осведомленность каждого о своей роли
в данном отношении, а также о правилах и ограничениях,
налагаемых данным отношением.
(С)Robert Viera, “Professional SQL Server 2000 Programming”

 

Типы отношений

  • Одного–к–одному (иммет смысл, когда в разных базах нужно хранить совпадающие данные или когда происходит превышение максимального размера данных строки)
  • Нуля– или одного–к–одному
  • Одного–ко–многим
  • Одного к –нулю, –одному или –многим
  • Многих–ко–многим (развязочные таблицы)

 

Объединения

INNER JOIN

Исключающее объединение (exclusive join). В результат выборки попадают только те записи таблиц, у которых есть соответствия в парной таблице по заданному условию.

LEFT|RIGHT [OUTER] JOIN

Включающее объединение (inclusive join). В результат выборки попадают записи из таблицы, стоящей слева/справа от JOIN соответственно. При этом данные из недостающей «парной» записи будут заполнены NULL.
FROM left_table LEFT JOIN right_table – включены все записи из левой таблицы left_table
FROM left_table RIGHT JOIN right_table – включены все записи из правой таблицы right_table

FULL JOIN

Включающее объединение (inclusive join). В результат выборки попадают не только записи, которые имеют соответствие в другой таблице, но и записи из обоих таблиц, для которых в соответствие в другой таблице не найдено. При этом данные из недостающей «парной» записи будут заполнены NULL.

CROSS JOIN

Перекрестное объединение (декартово произведение). Каждая запись из одной таблицы ставится в соответствие каждой записи из другой таблицы. Количество результирующих записей равно произведению количества записей в обоих таблицах.

Принципы упорядочивания нескольких JOIN’ов

В случае, если необходимо произвести объединение нескольких таблиц, нужно помнить о двух принципах:

  1. Все объединения левее JOIN воспринимаются как одиночная таблица для включения или исключения из запроса.
  2. Все объединения ПРАВЕЕ JOIN ТАКЖЕ воспринимаются как одиночная таблица для включения или исключения из запроса.

Следствием из этих принципов является следующая рекомендация для формирования сложных объединений:

  • Везде, где только можно, следует использовать INNER JOIN.
  • Если возникает необходимость использования OUTER JOIN – их нужно ставить последними, а в начале объединения размещаются INNER JOIN.

    P.S. Все вышеизложенное является общими "постулатами" теории реляционных баз данных, не привязанными к особенностям определенных СУБД.

    Нравится

    Поделиться

    10 комментариев

    Маша! Спасибо огромное! :)) Вспомнила универ и прослезилась...

    "Волжева Мария" написал:FROM left_table RIGHT JOIN right_table – включены все записи из левой таблицы right_table

    Кажется мне, что здесь закралась маленькая неточность.

    Ozzy получает особую благодарность за внимательность :)

    P.S. Исправила.

    Продолжаем уточнения :smile:

    "Волжева Мария" написал:

    Если возникает необходимость использования OUTER JOIN – их нужно ставить последними, а в начале объединения размещаются INNER JOIN.

    Это не совсем корректное утверждение.
    Дело в том, что в каждой СУБД собственный оптимизатор запросов и он сам решает как более правильно (на взгляд оптимизатора) построить запрос, т.е. последовательность объединений и индексов. Как правило оптимизатор строит свои планы выполнения на собранной статистике БД. Если статистика не актуальна, то и план выполнения (а следовательно и сам запрос) будут мягко говоря "тормознутыми".

    Если же окунуться еще глубже, то можно обнаружить что не всегда оптимизатор строит оптимальный план выполнения при актуальной статистике. В этом случае в работу подключаются хинты (Hints - подсказки) и разработчик может явно указать оптимизатору что делать, например изменить последовательность объединения, использовать другой индекс и.т.д.

    Евгений, спасибо за замечание.

    Но данная заметка не является попыткой рассмотреть все возможные варианты отработки запросов во всех возможных СУБД.

    Это есть общая рекомендация, и на уровне общей рекомендации она корректна.

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

    Да, и еще. Это просто мое мнение.
    Можно ли изложить статью более доступным языком с примерами. Мне кажется что часть людей на комьюнити не совсем понимают о чем именно идет речь, а тем более как это всё применимо к Террасофт CRM.

    Евгений, мне кажется, вы не понимаете цели этой заметки.

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

    Исходя из поставленной перед автором (собой) цели, изложение материала я все таки считаю корректным.

    P.S. Ваше замечание о том, что "последовательностью юнионов ни на что не влияет", (с возможными оговорками) может быть признано верным отнюдь не для всех версий и типов СУБД.
    С учетом этого рекомендация о порядке джоинов может считаться "хорошей практикой", особенно когда идет речь о работе с базами данных в целом. Не говоря уже о том, что в таком случае код будет нагляднее.

    Вы всё правильно говорите, только вот с Вашим PS мне тяжело согласиться. :smile:
    Т.к. комьюнити посвящено продуктам компании Террасофт, то и речь идет (наверно) о поддерживаемых СУБД: MS SQL, Oracle, Firebird. Про Firebird не скажу когда именно началась поддержка инструкций оптимизатора, а вот MS SQL 2000 уже их поддерживал и Oracle 8 тоже, а даты релизов этих продуктов 1999 и 1997 гг соответственно и их тяжело назвать относительно новыми поколениями.

    Если не ошибаюсь, то мы не декларировали поддержку Oracle 8. На момент выхода первой Terrasoft 3.0.0.x вробе бы была актуальна Oracle 9i.

    Про Oracle 8 я написал как пример когда появилась поддержка хинтов.

    Показать все комментарии