LINUX.ORG.RU

SQL, структура БД, не могу никак решить


0

0

Есть таблица MESSAGE, у неё есть поля M_ID, M_PARENT_ID - ссылается на другое сообщение в этой-же таблице

Есть задача - во время отображения web-страницы выбираются все сообщения для которых M_PARENT_ID = данному ID, и для каждого такого сообщеня надо узнать количество его потомков. Я просто добавил поле M_CHILDS_COUNT, при добавлении\удалении потомка соотв. модифицировал это поле и всё было прекрасно. Но сейчас в таблице появились права доступа на каждое сообщение и пользователь может смотреть только те сообщения, для которых MESSAGE.M_ACCESS_VIEW <= данный статус. Соответственно поле M_CHILDS_COUNT не всегда показывает правильное количество сообщений, которые может увидеть данный пользователь. Другой выход - делать так: сначала выбираем все нужные сообщения, потом для каждого сообщения делаем SELECT COUNT(*) FROM MESSAGE WHERE M_PARENT_ID = $id AND M_ACCESS_VIEW <= $status. Всё будет работать правильно, но в данном случае я выполняю не один запрос а N+1 запросов, и меня очень беспокоит производительность.

Я выписал плюсы и минусы каждого подхода, прокомментируйте пожалуйста, если я в чём-то не прав, или, может быть, есть другой вариант?

Использование M_CHILDS_COUNT
Плюсы:
быстрый запрос, например для получения кол-вы сообщений во всех темах при просмотре форума достаточно одного запроса.
Минусы:
В большинстве случаев это поле содержит некорректные данные для конретного пользователя.
Избыточность данных (хотя в данном случае это неявная избыточность, и это не очень плохо).
Дополнительные операции при добавлении\удалении сообщения.

Динамическое вычисление этого значения
Плюсы:
Возможность точного вычисления для конретного пользователя
Минусы:
для каждого сообщения надо делать свой запрос.
(возможно) низкая производительность БД при большом количестве сообщений в базе.
как следствие вышеперечисленного, возможна атака на сайт типа
/message.pl?id=<forum_id>;range=0-999999
^^^^^
думаю, даже не очень много подобных запросов легко перегрузят БД.
как вариант - ограничить макс. кол-во в range, но это плохой вариант.

Используется perl, mysql, у хостера стоит Linux, машина, судя по всему - далеко не мейнфрейм.

★★★★★

Вот слегка оптимизированный второй вариант:

Раз не хочется считать количество видимых комментариев - будем это количество хранить в отдельной таблице: Статус Тема Комменты Сколько коментов видит

2 3 1 1

6 3 2 3

7 3 2 5

9 3 1 6

2 4 5 5

7 5 2 2

9 5 1 3

6 6 6 6

Записи в эту таблицу добавляет скрипт добавляющий коммент

Вот пример добавления коммента:

Чел со статусом 3 добавил 1 комент в тему 3:

Статус Тема Комменты Сколько коментов видит

2 3 1 1

**3** 3 1 2

6 3 2 3+1

7 3 2 5+1

9 3 1 6+1

2 4 5 5

7 5 2 2

9 5 1 3

6 6 6 6

Т.о. нагрузка на сервер при добавлении коментария увеличится(за счет усложнения логики add_message.pl),а при просмотре форума - уменьшится (т.к. все расчеты уже сделаны).

Это решение будет работать быстрее, если клиетны форума чаще читают форум, чем срут в комментах, также, если max статус меньше количества тем в форуме.

Получение количества видимых коментов:

select

Сколько коментов видит

from

Новая_таблица

where

тема = Запрашиваемая тема and

статус <= статус_читающего;

Тем более врядли кому-то понадобится смотреть все темы форума - достаточно последних нескольких десятков.

klon
()
Ответ на: комментарий от klon

Спасибо, очень интересно.

Статусов, на практике, не больше десятка.

Заодно решается похожая задача - получение времени последнего обновления темы.

Legioner ★★★★★
() автор топика

>Динамическое вычисление этого значения
>Плюсы:
>Возможность точного вычисления для конретного пользователя
>Минусы:
>для каждого сообщения надо делать свой запрос.
>(возможно) низкая производительность БД при большом количестве >сообщений в базе.
>как следствие вышеперечисленного, возможна атака на сайт типа
>/message.pl?id=<forum_id>;range=0-999999
>^^^^^
>думаю, даже не очень много подобных запросов легко перегрузят БД.
>как вариант - ограничить макс. кол-во в range, но это плохой вариант.

Низкой производительности быть не должно - поле m_parent_id ведь проиндексированно?

dlomin
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.