Модераторы: skyboy

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Отображение количества непрочитанных тем, По типу "5 непрочитанных тем" 
:(
    Опции темы
fridkaratel
Дата 15.6.2012, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Не знаю, с какой стороны подойти... Поэтому хотелось бы услышать мнения, пусть даже с изменением структуры БД

Введение
Пользователи, но не линейный список, а в виде дерева.
Скажем, есть краевой офис, далее городской, далее районный, потом уже конкретное здание.
Пример: почта России.
Соответственно, пользователи организованы в виде дерева (о структуре ниже).

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

Пример
- Есть почта России
- Есть Дальневосточный филиал
- Сотрудница в 9-м отделе в 3 филиале пишет, что она не может выйти в админ. панель - проблема со входом.
- Заявка попадает в базу
- Эту заявку видят все вплоть до головного офиса в Москве
- Заявку читают системщики, и она отмечается как прочитанная
- Смотрят, что никто в городе это исправить не может, и пишут комментарии
- Так заявка доходит до окружных системщиков (поднялась уже на 8 уровней вверх по дереву)
- Окружные системщики поняли, что надо делать, добавили комментарий "Завтра приедем" и приняли заявку

База данных
Использую MySQL + PHP

Таблица `user`:
UserId | ParentId | Name
Подчинение не по типу групп "Бухгалтерия", "Менеджеры".
Тут вариант такой: Петров (директор филиала), у него замы (Тыров и Монетин), у каждого из замов по профилю другие сотрудники, у тех в подчинении свои и т.д.

Таблица `document`:
DocumentId | UserId | Title | Text
UserId - кто добавил заявку (документ).
Если добавил директор филиала, то нижестоящие сотрудники не видят эту заявку, а вот выше по леснице видят.

Пример дерева пользователей
Код
Директор округа
  Представитель
    Автослесарь
      Мойщик авто
      Мойщик авто
      Главный по двигателям
        По выхлопной части
        По улучшению качества топлива
          Помощник
  Директор филиала
    Зам. директора по фин. части
    Директор по рекламе
      Зам по рекламе
        Программист
        Программист
        Кассир
          Помощник кассира
  Директор филиала
    Зам. директора
    Уборщица
      Помощница уборщицы
      Выносщик мусора
    Гл. бухгалтер
      Бухгалтер
      Бухгалтер
        Кассир
          Помощник кассира
          Уборщица в приёмной

1. Вложенность может быть до 200 уровней, может и больше, но не больше 1000 (я надеюсь smile )
2. Ввиду, скажем, расширения фирмы, будут добавляться новые пользователи, некоторые будут удаляться (увольняться).
3. Родители в дереве меняться практически не будут (за очень-очень редким исключением)

Отображение изменений
Код
Директор округа                       {видит}
  Представитель                       {видит}
    Автослесарь                       {видит}
      Мойщик авто                     {видит}
      Мойщик авто                     {видит}
      Главный по двигателям           {видит}
        По выхлопной части            {добавил документ}
        По улучшению качества топлива {не видит}
          Помощник                    {не видит}
  Директор филиала                    {не видит}
    Зам. директора по фин. части      {не видит}
    Директор по рекламе               {не видит}
      Зам по рекламе                  {не видит}
        Программист                   {не видит}
        Программист                   {не видит}
        Кассир                        {не видит}
          Помощник кассира            {не видит}
  Директор филиала                    {не видит}


Основным вариантом думал - это:
- Создать таблицу `document_view`: ViewId | DocumentId | UserId | ViewDate
- При просмотре документа добавлять запись в эту таблицу
- При добавлении комментария (изменении документа) удалять все записи с необходимым DocumentId
- Показывать количество через JOIN, но...

Вот тут, собственно, и начинается сложность... smile
Как отобразить, сколько документов с изменениями, чтобы в дальнейшем показать список этих самых документов?
Ведь, надо показать только количество документов, которые доступны в ДВ округе, то есть как-то заиспользовать дерево пользователей (вложенность)?

P.S.:
К почте России никакого отношения не имею smile
Взял просто для примера, можно взять также вариант заправки, закусочной, того же ДНС и т.д.

Это сообщение отредактировал(а) fridkaratel - 15.6.2012, 12:58
PM   Вверх
Akina
Дата 15.6.2012, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Ну первое - это сразу перестройте структуру таблицы user на использование nested set, сильно упростит жизнь в будущем.
И второе - не предусмотрена система комментирования комментария. Может, Пупкин не разобрался и фигню написал? так об этом нужно оставить комментарий, причём привязанный не к доукменту, а к комментарию именно Пупкина. Так что документы с комментариями придётся тоже хранить в виде дерева. И тоже в форме nested set, вероятно.

Цитата(fridkaratel @  15.6.2012,  13:20 Найти цитируемый пост)
Как отобразить, сколько документов с изменениями, чтобы в дальнейшем показать список этих самых документов?

У них дата комментирования больше даты просмотра. Всего-то...



--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
fridkaratel
Дата 15.6.2012, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Akina, поправил текст поста... исправил на более соответствующий...

Проблема в том, что надо:
- Сначала выбрать пользователей, которые стоят ниже меня (то есть того, кто смотрит, напр., директор округа)
- Затем выбрать заявки (документы) с изменениями
- Затем удалить из выдачи те документы, которые не относятся к пользователям

Это сообщение отредактировал(а) fridkaratel - 15.6.2012, 13:05
PM   Вверх
Akina
Дата 15.6.2012, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(fridkaratel @  15.6.2012,  13:43 Найти цитируемый пост)
выбрать пользователей, которые стоят ниже меня (то есть того, кто смотрит, напр., директор округа)

Nested set в полный рост

Цитата(fridkaratel @  15.6.2012,  13:43 Найти цитируемый пост)
выбрать заявки (документы) с изменениями

Тривиальный отбор по наличию потомка

Цитата(fridkaratel @  15.6.2012,  13:43 Найти цитируемый пост)
удалить из выдачи те документы, которые не относятся к пользователям

Фильтрация по подзапросу


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
fridkaratel
Дата 15.6.2012, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Akina, спасибо за ответы.

1. Ох, и так, и так пытался обойти nested sets.. Видимо, пришло время smile

2. Вопросов нет, тут понятно

3. То есть через WHERE UserId IN (SELECT...)?
PM   Вверх
Akina
Дата 15.6.2012, 14:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(fridkaratel @  15.6.2012,  14:19 Найти цитируемый пост)
То есть через WHERE UserId IN (SELECT...)? 

Как вариант - если не получится построить запрос с прямым связыванием таблиц.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
fridkaratel
Дата 15.6.2012, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Подитог...

1. Таблица пользователей через nested sets
2. Таблица заявок (документов): DocumentId | UserId (необходимый минимум)
3. Таблица комментариев к заявкам: CommentId | DocumentId | UserId | CreationDate (это минимум, будем считать, что комментарии комментировать нельзя)
4. Таблица просмотров заявок: ViewId | DocumentId | UserId | ViewDate

Akina, не совсем понял про прямое связывание...
Получить количество заявок с непрочитанными документами можно одним запросом?

Как-то не совсем понимаю, как можно организовать хранение комментариев через nested sets, ведь сама структура nested sets подразумевает как можно меньшее количество добавлений в базу, или нет?

Это сообщение отредактировал(а) fridkaratel - 15.6.2012, 16:01
PM   Вверх
Akina
Дата 15.6.2012, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(fridkaratel @  15.6.2012,  16:59 Найти цитируемый пост)
сама структура nested sets подразумевает как можно меньшее количество добавлений в базу, или нет?

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

Цитата(fridkaratel @  15.6.2012,  16:59 Найти цитируемый пост)
не совсем понял про прямое связывание...
Получить количество заявок с непрочитанными документами можно одним запросом?

Возможно. А возможно, что и нет. Это надо будет смотреть конечную структуру... а если да - то смотреть эффективность обеих версий запросов.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
fridkaratel
Дата 16.6.2012, 04:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Akina, спасибо за все ответы! ;)

Перестроил таблицу для хранения пользователей на nested sets...
Возник вопрос - можно ли будет выбрать список пользователей вверх по дереву, но до определённого условия?

Например, автослесарь согласовал с директором и сказал, что все вопросы касаемо автомобилей не поднимать выше меня.
Я - конечная инстанция.
В базе бы вводим доп. столбец "Breaker", ставим туда true (1).
Если директор смотрит заявки, то он не видит заявок, которые от автослесаря (breaker'а и ниже по лестнице).
Такое получится сделать одним запросом?


Касаемо моего вопроса, реализовал так (на тестовых таблицах):
Код
SELECT
    b.Title
    FROM
        `my_book` b
        LEFT JOIN
            `my_book_view` bv
            ON
                b.BookingId=bv.BookingId
                AND
                b.LastUpdate<bv.ViewDate
        INNER JOIN
            `my_tree` u
            ON
                u.left_key>=PARENT_LEFT_KEY
                AND
                u.right_key<=PARENT_RIGHT_KEY
                AND
                u.id=b.UserId
    WHERE
        bv.ViewDate IS NULL

Может, есть какие замечания?

Это сообщение отредактировал(а) fridkaratel - 16.6.2012, 07:55
PM   Вверх
fridkaratel
Дата 17.6.2012, 07:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



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

Вот такой запрос на выборку измененённых заявок:
Код
SELECT
    b.BookingId,
    u.Name,
    bv.ViewDate
    FROM
        `booking` b
        INNER JOIN
            `user` u
            ON
                b.UserId=u.UserId
                AND
                u.Parents LIKE "%:{USERID_HERE}:%"
        LEFT JOIN
            `booking_view` bv
            ON
                bv.BookingId=b.BookingId
                AND
                bv.UserId={USERID_HERE}
                AND
                bv.ViewDate>b.LastUpdate
        WHERE
            bv.ViewDate IS NULL


Всё же, nested sets больше подходит для статичного дерева...
Если надо переместить элемент в другую ветку или же удалить родителя и сместить детей вверх к над-родителю, то надо та-а-кое нагородить, что ###... smile

Поэтому, как было materialized path, пусть так и останется...
Да и администрировать это дело легче нежели NS - глянул в phpmyadmin - и всё понятно, что и где.

Не знаю, насколько быстрый мой вариант выборки, может будут советы/замечания?
А то, как-то LIKE мне не нравится, но думаю, что он лучше, чем IN, т.к. в IN может быть и 40 элементов smile

Это сообщение отредактировал(а) fridkaratel - 17.6.2012, 07:49
PM   Вверх
Akina
Дата 17.6.2012, 20:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 45
Всего: 454



Цитата(fridkaratel @  17.6.2012,  08:05 Найти цитируемый пост)
Если надо переместить элемент в другую ветку или же удалить родителя и сместить детей вверх к над-родителю, то надо та-а-кое нагородить, что ###... 

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

Цитата(fridkaratel @  17.6.2012,  08:05 Найти цитируемый пост)
LIKE мне не нравится, но думаю, что он лучше, чем IN

В общем случае это неверно.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
fridkaratel
Дата 18.6.2012, 04:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Цитата
хранимую процедуру?

Читал про хранимые процедуры... Читал про триггеры...
Минус: Большие и сложные конструкции
Плюс: Уже всё готово - заменяй поля и вставляй smile

Попутно, пока изучал, наткнулся на страницу, где подробно рассказывается о трёх методах хранения деревьев и прилагаются результаты тестирования скорости...
Как-то NS не очень-то и быстро работает...
Да и... для меня в понимании NS сложноват - а MP открыл в phpmyadmin, и всё сразу видно...

Цитата
В общем случае это неверно. 

То есть? Расскажи поподробней, пожалуйста.
Конечно, я могу всего не знать, т.к. MySQL у меня не по профилю, я не специалист по БД... ;)

Примечание
У меня будет довольно часто меняться структура пользователей (дерева карьерной лестницы, как в моём примере).
Основной кастет (директора, замы) меняться практически не будут, но вот подчинённые ноды (работники) могут добавляться (70%), удаляться (10%) и перемещаться (20%).
Если использовать MP, то всё сводится к REPLACE WHERE LIKE %...
Единственное, что вижу плохого в MP - это то, что надо хранить весь путь предков в TEXT, что увеличивает размер БД, но... ну и ладно, пусть увеличивает smile

К тому же, я могу в MP (как писал выше) сделать breaker'а без особых проблем - просто обрезать ему список предков до него самого (и всем дочерним нодам соответственно)...
Во-от...
PM   Вверх
Zloxa
Дата 18.6.2012, 08:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 53
Всего: 161



Цитата(fridkaratel @  18.6.2012,  05:54 Найти цитируемый пост)
но вот подчинённые ноды (работники) могут добавляться (70%), удаляться (10%) и перемещаться (20%).

Здесь важен не столько сам факт возможности модификации дерева, сколько важно отношение количества модификаций к количеству чтений.

Я так скромно полагаю, что врядли оргструктура предприятия будет реорганизовываться ежеминутно, ежечасно. Полагаю модифицироваться она будет от силы пару, тройку раз в месяц. Врядли в режиме конкурентного досутпа. Отбор же заявок, вероятно, будет производиться весьма и весьма часто.
Цитата(fridkaratel @  17.6.2012,  08:05 Найти цитируемый пост)
А то, как-то LIKE мне не нравится, но думаю, что он лучше, чем IN, т.к. в IN может быть и 40 элементов

Лайк с "%" в начале лайкпаттерна исключает возможность использования индекса. In вполне может использовать индекс. MP позволит сэкономить вам трошку ресурса на реорганизации струтуры, что у вас будет происходить весьма редко, но существенно замедлит отбор, который, вероятно, будет весьма част.


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
fridkaratel
Дата 18.6.2012, 09:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 221
Регистрация: 22.10.2007
Где: Error connect to MySQL Da...

Репутация: нет
Всего: нет



Zloxa, большое спасибо за ответы!

На скольки записях будет чувствоваться превосходство NS перед MP?
Планируется, что пользователей будет не больше 100 000, вложенность - максимум 300 уровней.

Отбор
Да, редактироваться будет куда меньше раз, чем считываться smile
Вставка записей: ~100 раз в месяц
Удаление: ~10 раз в месяц
Перемещение: ~10 раз в месяц

1. То есть, всё же заиспользовать NS?

2. Перейти с LIKE на IN?
Есть на уме вариант такой:
- Выбрать Parents у пользователя
- На PHP разложить в массив
- Задействовать IN вместо LIKE

Сейчас же использует реализация одним запросом через JOIN ... LIKE %.

P.S.:
Кстати, думал сделать отдельную таблицу, в которой был бы список всех родителей, относящихся к элементу по типу UserID => ParentId.
Например, путь ":1:2:3:4:5:13:" выглядел бы в таблице так:
13 - 5
13 - 4
13 - 3
13 - 2
13 - 1

Но потом прикинул, сколько же записей будет, если будет 100 000 пользователей с 300 уровнями вложенности... smile

Это сообщение отредактировал(а) fridkaratel - 18.6.2012, 09:05
PM   Вверх
Zloxa
Дата 18.6.2012, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 53
Всего: 161



Цитата(fridkaratel @  18.6.2012,  10:04 Найти цитируемый пост)
думал сделать отдельную таблицу

Если я правильно понял, это реаляционная реализация материализованного пути.
Ее преимущество - возможность использования индекса при отборе.
Недостаток - объем.
Цитата(fridkaratel @  18.6.2012,  10:04 Найти цитируемый пост)
Но потом прикинул, сколько же записей будет, если будет 100 000 пользователей с 300 уровнями вложенности...

3 млн? Что вас пугает? Вы же не собираетесь постоянно сканировать эти 3млн. Я так понимаю вам из этих 3млн единоразово, редко придется отбирать более 300 записей. Индексы придуманы как раз для таих случаев.

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

Цитата(fridkaratel @  18.6.2012,  10:04 Найти цитируемый пост)
На скольки записях будет чувствоваться превосходство NS перед MP?

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

Добавлено через 8 минут и 27 секунд
Цитата(fridkaratel @  18.6.2012,  10:04 Найти цитируемый пост)
Вставка записей: ~100 раз в месяц

=3 раза в день.
Фирма действительно нанимает по три сотрудника в день?
А увольняет раз в три дня?

Хорошая, динамично растущая фирма.  smile 

Как бы там ни было, мне кажется, если "100 раз в месяц" окажется проблемой, мне кажется, вполне можно свести регламентом к 1 раз в день, пакетным заданием, в ночное время суток. Врядли новонанятый сотрудник должен получать возможность принимать заявки сразу же, в день его оформления.


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Составление SQL-запросов | Следующая тема »


 




[ Время генерации скрипта: 0.0943 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.