@turbomen24

Нормализация базы данных?

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

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

Хорошо, создаём таблицы:
"Музыканты"
"Инструменты"
"Группы"
"Составы группы"
"Музыканты в составе"
"Инструменты музыканта в составе".

Таким образом на выходе, если я захочу добавить новую страницу группы, сколько раз придётся сделать INSERT? Даже если данные музыканты и инструменты уже изначально есть в таблице, получится следующее:

1. Вставить запись о новой группе в таблицу "Группы".
2. Вставить запись о первом составе в таблицу "Составы группы".
3. Вставить запись о втором составе в таблицу "Составы группы".
3. Вставить запись о музыканте-1 первого состава в таблицу "Музыканты в составе".
4. Вставить запись о первом инструменте музыканта-1 в таблицу "Инструменты музыканта в составе".
5. Вставить запись о втором инструменте музыканта-1 в таблицу "Инструменты музыканта в составе".
6. Вставить запись о музыканте-2 первого состава в таблицу "Музыканты в составе".
7. Вставить запись о первом инструменте музыканта-2 в таблицу "Инструменты музыканта в составе".
8. Вставить запись о музыканте-3 первого состава в таблицу "Музыканты в составе".
...

А если их 10 в составе музыкантов и самих составов было 3-4? Так мои 10 запросов легко превратятся в добрую сотню, и всё чтобы добавить вроде простейшую информацию...
Мне кажется, или это будет слишком много? Ведь хочется не только разбить структуру базы на минимально-полезную информацию, но и чтобы не получить большого числа запросов, которые потребляют память и т.д., тем более если это всё относится к информации, которая будет очень часто обновляться...
SELECT-запросы ещё попроще будут, но вот INSERT, и тем более что всё связано внешними ключами, к примеру, для таблицы "Музыканты в составе" нужен PRIMARY KEY таблицы "Составы группы" для идентификации, а его сначала нужно получить в php и только потом делать следующий INSERT в другую таблицу, то есть все эти запросы даже не одной транзакцией будут идти.

Что же теперь, через запятую перечислять ID нужных элементов и всё в одной-двух таблицах? Но так невозможно сделать внешние ключи, что тоже вроде не очень хорошо...

В общем, спасибо, если вы это прочитали, мне бы хотелось увидеть, как бы вы поступили.
  • Вопрос задан
  • 224 просмотра
Решения вопроса 2
@tukreb
Почитайте книгу
"Программирование баз данных SQL. Типичные ошибки и их устранение"
И у вас отпадёт часть вопросов.
Ответ написан
agoalofalife
@agoalofalife
Team Lead
Часто бывает что выгодно делать именно денормалазацию данных. Тут как везде борьба компромиссов.
Я тут накидаю своих размышлений а у вас будет почва для дополнительных раздумий.
Для наглядности я сюда схему прикрепил
5fd339050f4b3128986508.png

Нормализация
Группы, инструменты, музыканты сейчас нормализованы, и они храняться в отдельных таблицах.
Преимущества:
- Мы можем переиспользывать эти данные
- В других таблицах, это внешний ключ и мы получаем индекс
- База следит за целостностью информации(то есть, если мы добавляем новый состав, группа должна существовать. Если мы захотим удалить группу, база данных может нам запретить это сделать так как у нас есть записи в таблице состав группы. Это уже настройки restrict or update) На первый взгляд не самое очевидное, но важное преимущество тем не менее.
И вот почему, мы можем денормализовать эти таблицы, добавляя как строку в pivot table(таблица составов и остальные что ниже на диаграмме) вместо внешнего ключа:
- Меньше запросов при insert
- Если сделать индекс, не надо ходить за id в верхние таблицы, но ...
Собственно весь мир стремиться к хаосу и код не исключение. Давая повод для вставки простой строки, мы провоцируем все это на хаос. Может вы знаете конечный список групп, но кто то не знает и может вставить что угодно, соответственно из за этого будет проблемы.

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

Работа в самом коде
Возможно вас пугает кол-во вставок при такой архитектуре. Это реляционная база данных, и связи одно из главных вещей(преимуществ) и она отражена в названии.
В коде это организуется конечно иначе, в зависимости от использования подхода к работе с базой.
Это может быть:
- Active Record(Eloquent - laravel)
- Data mapping (Doctrina - Symfony)
Не углубляясь в подробности, часть будет инкапсулирована и вставка будет проще(в самом коде).
Зависит так же от интерфейса, при том примере что у вас выше:
В окне пользователя будет вводиться сразу вся информация.
И это не всегда так, в зависимости от подхода(может быть SPA приложение), в одном окне может добавляться состав группы, в другом из form select, набираться музыканты в этот состав.
Резюмируя - реляционная база это кончено связи. Можете попробовать организовать такое в NoSQL. Таблицы что выше, кто - то называет их справочниками.(можно организовать кэш по ним, если они не изменяются, а только переиспользуются и добавляются новые).
Надеюсь хоть в чем то вам помог.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы