Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MySQL > Как бы вы поступили


Автор: maxipub 12.5.2016, 13:36
Добрый день!

Понимаю, вопрос более философский, если так можно сказать. smile

Предположим, пишу движок форума. Есть таблица разделов (forum), и таблица топиков (topic). У разделов есть настройки, в том числе и его включенность (forum_enabled). Понятно, что если раздел отключен, то его не нужно показывать. При этом по логике, ни где не нужно выводить и список топиков этого раздела (например, при просмотре всех топиков пользователя).

Поначалу я просто джойнил к топикам таблицу форумов по forum_id, добавляя в условие forum_enabled=1. Но движок развивается, и вот появляются категории пользователей (user_groups). Для разных категорий пользователей свои настройки, в том числе и права просмотра различных разделов. Так что возможна ситуация, когда раздел то не отключен, но у пользователя нет прав для его просмотра. Следовательно, для данного конкретного пользователя он ведет себя как отключенный.

В итоге сейчас получается:

Код
SELECT ... FROM topic INNER JOIN forum ... INNER JOIN user_groups ... WHERE forum.forum_enabled=1 ...


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

Вы бы в данном случае оставили все как есть? Или добавили бы в topic небольшое по весу поле forum_enabled, которое будет дублировать значение forum.forum_enabled для текущего forum_id? Это позволит убрать из запроса INNER JOIN forum, оставив только условие в WHERE. На размер таблицы сильно не повлияет. Значение topic.forum_enabled в данном случае будет задаваться при создании топика. А изменяться только при изменении настроек включенности разделов форума, что бывает крайне редко, это практически исключительная ситуация. Да и обновляться такие данные будут быстро.

Ваше мнение? smile 

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

Автор: Akina 12.5.2016, 15:15
Моё мнение - отсутствие нормального анализа предметной области, попытка решить задачу кавалерийским наскоком.

Автор: ksnk 12.5.2016, 16:30
В каждый конкретный момент существует единственный пользователь - посетитель сайта. Список доступных/запрещенных  разделов и топиков - `статическая` информация, которую можно вычислить при входе и закэшировать в данных пользователя. Соответственно, в where можно вставить ` AND topic.id not in (123,234,345,...) ` Сама структура топиков и форумов при этом не меняется, sql остается примерно таким как и был. 

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

Автор: Zloxa 12.5.2016, 16:36
Цитата(maxipub @  12.5.2016,  14:36 Найти цитируемый пост)

Вы бы в данном случае оставили все как есть? Или добавили бы в topic небольшое по весу поле forum_enabled, которое будет дублировать значение forum.forum_enabled для текущего forum_id? 

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

Цитата(maxipub @  12.5.2016,  14:36 Найти цитируемый пост)
Ваше мнение? 

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

Автор: Zloxa 12.5.2016, 17:03
Цитата(Zloxa @  12.5.2016,  17:36 Найти цитируемый пост)
отказ от нормализации приводит к усложнению логики работы с данными, к увеличению ошибок.

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

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

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

Автор: barmaley4ik 13.5.2016, 11:46
Не претендую на правильность, но как вариант добавил бы в юзергрупп столбец topic_id с типом varchar(...) ну или tetx и запихивал бы туда для каждой группы нужный топик для доступа через спец.символ, например ~, а в запросе использовал match... Для практической реализации, нужно тестить

Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/Kak-by-vy-postupili-id57345d47ae2015fa148b4567#findElement_E7045_5735944dae201575255cd537_0

Автор: maxipub 13.5.2016, 18:28
Спасибо всем за мнения. А отдельное спасибо Zloxa, Ваша точка зрения мне ближе всего.

Цитата(Zloxa @  12.5.2016,  17:03 Найти цитируемый пост)
Допустим мы одновременно меняем статус форума и добавляем топик. В тот момент, когда мы считываем статус форума, он еще не изменен другой сессиией. В тот момент, когда мы вставляем новый топик, он уже изменен. В результате мы получаем рассогласованные данные. Для разных топиков одного и того-же форума у нас проставлен различный статус форума.

Кстати, у меня есть другие моменты, где возможна подобная ситуация. Я одно время парился, но потом забил на это. Ведь вероятность такого, пусть даже на форуме 100'000 пользователей ежедневно, практически нулевая. Т.е. в теории такое может случиться, но на практике Вы с таким сталкивались в жизни? smile 

Автор: Zloxa 14.5.2016, 10:24
Цитата(maxipub @  13.5.2016,  19:28 Найти цитируемый пост)
 Я одно время парился, но потом забил на это.

Надо понимать, что требования к согласованности данных форумного движка, и, скажем, ПО, начисляющего Вам зарплату - очень сильно разнятся. Забили меж тем - зря. Именно благодаря тому, что на форумном движке не страшно потерять согласованность, он - замечательный полигон для упражнений и наработки практики как ее не терять  smile 
Цитата(maxipub @  13.5.2016,  19:28 Найти цитируемый пост)
 Т.е. в теории такое может случиться, но на практике Вы с таким сталкивались в жизни?   

Конечно же сталкивался. 365 ружей стреляющих раз в год будут стрелять каждый день.

Автор: maxipub 16.5.2016, 13:28
Zloxa, кстати, вот я что-то упустил из виду. Вот согласование это. Может быть ситуация, когда непосредственно перед создание темы изменяются настройки, и тема создается с несогласованными данными. Да. Но ведь после изменения настроек все равно будет происходить обновление данных, и все вернется на круги своя?

Я понимаю, что такое в принципе само по себе не есть хорошо. Когда был молодым идиалистом, тоже любил все полировать. Над ерундой, которой другие уделяли 2 минуты, мог две недели сидеть. Сейчас понимаю, что самое ценное что есть - время. Поэтому не стоит сильно заморачиваться и делать свою работу на все 100%. В большинстве случаев 80% хватает с головой, не распыляясь на мелочи.

Хоть в любом случае, если можно сделать лучше, то лучше сделать лучше. smile 

Автор: Zloxa 16.5.2016, 13:46
Цитата(maxipub @  16.5.2016,  14:28 Найти цитируемый пост)
Может быть ситуация, когда непосредственно перед создание темы изменяются настройки, и тема создается с несогласованными данными. Да. Но ведь после изменения настроек все равно будет происходить обновление данных, и все вернется на круги своя?

Я говорил о случае добавления нового топика в форум с одновременным отключением форума. Когда:
Сессия 1
Код

select forum_enabled from forum where id = :forum_id;

Сессия 2
Код

update forum set forum_enabled = 0 where id = :forum_id;
update topic set forum_enabled = 0 where forum_id = :forum_id;
commit

Сессия 1
Код

insert into topic(forum_enabled) values (1);


Цитата(maxipub @  16.5.2016,  14:28 Найти цитируемый пост)
 В большинстве случаев 80% хватает с головой, не распыляясь на мелочи.

Принцип Парето гласит что 20% усилий дают 80% результата. Вероятно вы таки делаете свою работу на 20% а не на 80  smile

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)