Mysql Помогите понять нормализацию

bazooka

Новичок
Когда стоит делить данные на таблицы, а когда можно внести в одну таблицу 50 полей и не паррится.
Вот пример из википедии про 2НФ:
https://ru.wikipedia.org/wiki/Вторая_нормальная_форма
В данном случае разбивают на 2 таблицы только потому что первичный ключ образует пара атрибутов {Сотрудник, Должность}:? Т.е. если бы первичный ключ был один и уникальный (например логин) то делить на 2 таблицы не потребовалось бы?

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

Тот же вопрос про третью нормальную форму https://ru.wikipedia.org/wiki/Третья_нормальная_форма Если бы у каждого сотрудника был свой телефон а не отдела, то разделение на 2 таблицы так же не потребовалось бы? Может кто-то привести примеры 3НФ в разработке сайтов именно?
 

AnrDaemon

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

hell0w0rd

Продвинутый новичок
Нормализация обычно подразумевает, что таблицы можно связать отношением "один ко многим"
А вот и нет, посмотри 1НФ
bazooka, если вдаваться в теорию - join является базовым понятием в реляционной алгебре, так что им явно не стоит пренебрегать. Для оптимизации используют вьюхи, в которых денормализуют данные, если это требуется, но в вебе, на сколько я знаю на этот вариант забивают и кешируют результаты тяжелых выборок.
У отдела также мог быть начальник, проект, и куча всего - так что это вполне реальный вариант в вики.
 

bazooka

Новичок
Я просто не очень понимаю у меня есть юзеры и по ним кроме базовой инфы (пароль, е-майл, дата регистрации) есть:
1. количество созданных им тем
2. количество ответов (надо будет определить лидера по ответам в каждом разделе)
3. количество лайков к этим сообщениям (так же сообщение с наибольшим кол-ом лайков)
4. ответов за сутки
5. лайков за сутки
6. сумма всех лайков юзера (что-то типа кармы)
7. рефералов юзера

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

hell0w0rd

Продвинутый новичок
bazooka, можно выносить - можно не выносить.
http://habrahabr.ru/post/64524/ - вот статейка на эту тему.
Если выносит то во вьюху, если не выносить - то вешать триггеры и пересчитывать при изменении зависимых полей.
 

Вурдалак

Продвинутый новичок
Необязательно хранить количество лайков и прочее в СУБД, можно взять какое-нибудь персистентное key-value хранилище типа Redis, LevelDB, etc. Т.е. и user_id лидера там же хранить, а потом просто из СУБД этого юзера доставать. Такие хранилища подходят намного лучше для счетчиков.
 

WMix

герр M:)ller
Партнер клуба
В зависимости от цены проекта, типа предприятия, упора на данные, критерии нормализации будут вариировать. Для веба действительно лучше денормализировать для достижения быстрого чтения, но тутже нужно думать о возрастающей цене поддержки таких баз, или возрастающей цене програмного обеспечения, которое должно уметь обратно нормализировать. Граница добра и зла
 

bazooka

Новичок
Необязательно хранить количество лайков и прочее в СУБД, можно взять какое-нибудь персистентное key-value хранилище
да я никогда раньше с такими не работал, у меня на сервере софт для них не стоит, а такую таблицу в таких хранилищах тоже можно и лучше хранить?
 

Вурдалак

Продвинутый новичок
Нет. Храни лайки в СУБД, короче, и не парься. Единственное, можно было бы «количество лайков за сутки» вынести в отдельную таблицу (likes_history), где бы указывалась дата: likes_quantity | date. Это естественным образом бы показывало актуальное на данный момент количество лайков за сутки без очисток кроном.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Вурдалак, WMix, сказочники-фантазеры вы. Денормализация - исключительное явление, на базах > 100 гб при нагрузках в десятки миллионов insert/update в сутки нормализованная структура отлично работает.
Базу нормализовывать надо - без фанатизма, enum и set полезны, каждый стоковый столбец с неуникальными значениями не надо выносить в отдельную таблицу, но постоянный балаган типа "Для веба действительно лучше денормализировать" - это ламеры с серьезными базами не работали.
Чем больше проект, чем больше разработчиков - тем важнее, чтобы нормализация соблюдалась.
Единственная форма денормализации, которая действительно требуется для производительности - это партицирование.

Приходит ко мне одно чмо на собеседование и говорит: "Мы на production все внешние ключи сносим нахрен! Для производительности."
 
Последнее редактирование:

bazooka

Новичок
grigori а из моего перечня что бы вы вынесли в отдельные таблицы.

можно было бы «количество лайков за сутки» вынести в отдельную таблицу (likes_history), где бы указывалась дата: likes_quantity | date.
А мне на надо за все дни, мне надо за последние сутки только, поэтому ночью хочу высчитывать разницу и хранить её в отдельном поле, за следующий день затирать новым значением
 

WMix

герр M:)ller
Партнер клуба
Ну конечно, join быстрее чем cache записаный в mongo. Даешь каждому пользователю по коннекшину в оракле!
Не суди так строго, конечно же данные должны быть нормированы, важно только понимать на сколько.
А так да граница добра и зла. Для имен пользователей ты не строишь отдельную таблицу
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
WMix, mongo is web scale! :D

дело в том, что человек задал вопрос о нормализации базы данных, отвечать рассказом про оптимизацию через key-value-хранилище - некорректно.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
1. количество созданных им тем
это не надо хранить, это считается select count(*) from posts where author=:user_id
2. количество ответов (надо будет определить лидера по ответам в каждом разделе)
select count(*) from posts where group by author where topic_id=:topic_id
3. количество лайков к этим сообщениям (так же сообщение с наибольшим кол-ом лайков)
4. ответов за сутки
5. лайков за сутки
6. сумма всех лайков юзера (что-то типа кармы)
7. рефералов юзера
мне лень составлять все эти запросы

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

MiksIr

miksir@home:~$
Далеко не всегда можно позволить себе даже редиску. Ибо есть четкие требования к ПО. Если кто-то работал в компании "что хочу, то и использую" - это не значит, что так везде. И что теперь, рейтинги будем каждую выборку считать?
Более того, денормализация в пределах одной СУБД часто бывает дешевле как в разработке, так и в обслуживании, чем дополнительные хранилища.
Почему, выгребая товар, я должен лезть за рейтингом в какую-то дополнительную key-value, если можно положить его в товар и заботливо обновлять триггером или логикой в модели? А сложные выборки положить в материализованную вьюху.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
MiksIr, фантазии о требованиях к у ТС в студию plz :)
с щитаю, что требование сводится к обслуживанию 2х юзеров в сутки

И что теперь, рейтинги будем каждую выборку считать?
да, до тех пор, пока не узнаем, почему это невозможно

Почему, выгребая товар, я должен лезть за рейтингом в какую-то дополнительную key-value, если можно положить его в товар и заботливо обновлять триггером или логикой в модели?
потому что это правильное решение для реляционной базы данных,
а писать приложение в расчете на триггер - это зависимость, хрупкость и бессонные ночи DBA и админов, когда базка упадет, и ее не получится поднять из бекапа
 
Последнее редактирование:

MiksIr

miksir@home:~$
Да не, причем тут ТС, я в общем и целом. Ты же тоже говорил не про ТС, а про "Денормализация - исключительное явление".
У меня бывает, ибо на той стороне бывают серьезные заказчики со своими CIO, службами безопасности и прочими тараканами. Да даже и без них, я 10 раз подумаю - стоит ли заводить отдельный кеш, если можно положить в ту же базу.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Я говорил конкретно про вопрос, заданный ТС, я не телепат и не фантазирую про службы безопасности.
В общем случае делать денормализацию не надо. Надо строить индексы и оптимизировать запросы.
Если какая-то исключительная проблема не решается через индексы - надо рассматривать ее индивидуально.
 

MiksIr

miksir@home:~$
да, до тех пор, пока не узнаем, почему это невозможно
Не, логика "прем в лоб, а уже потом денормализуем по факту" - она в чем-то верная, но все же иногда срабатывает опыт.

Банальное сравнение "выборка товара по pk" vs "выборка товара по pk + join с группировкой" уже намекает на слишком большой вклад во время выполнения за счет рейтинга. И это даже в простом случае, когда рейтинг мы считаем существующей агрегатной функцией, типа average. А если там логика сложнее, например, функция зависимости от числа голосов?

Или еще банальное - цепочка "страна" - "фабрика" - "коллекция" - "товар", нужно вывести список стран, но только не тех, по которым товара нет активных товаров. Будешь плевать на денормализацию и в выборке стран приделывая еще три джойна? Или сразу соломку подстелешь?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
логика "предварительная оптимизация - зло" - прямое следствие Бритвы Оккама, и это мое основное правило в работе :)
я стараюсь делать как можно меньше по каждой задаче - так я решаю больше задач в период времени, а в свободное время могу путешествовать

выборка товара по pk + join с группировкой
прекрасно работает в крупнейших интернет-магазинах рунета ;)
Будешь плевать на денормализацию и в выборке стран приделывая еще три джойна? Или сразу соломку подстелешь?
буду делать 10 join-ов - на правильных индексах отлично работает даже на сотнях тысяч записей в таблицах, пока мне не предоставят требования, которым это решение не удовлетворяет.
Требованиям вроде "отрисовка страницы меньше, чем за 0.5 сек" это решение подходит.
Сейчас мой каталог на join-ах вообще без кешей отдается меньше, чем за 0.1 сек., меня устраивает.
 
Последнее редактирование:
Сверху