бейте палками 😂
Делаю структуру БД для микросервиса технической поддержки.
Можете, пожалуйста, посмотреть - правильно ли сделал.
У текущей реализации есть некоторые проблемы
1. Вносить данные нужно с помощью транзакций, так как при создании тикета на сайте мне нужно заполнить несколько таблиц - создать тикет, создать сообщение в тикете, обновить статус тикета, назначить менеджера на тикет. Если хотя бы одно из этих действий в бд не прошло - от остальных толку нет.
2. При выводе пользователю его тикетов вместе со статусом и прочими данным в запосе будет слишком много JOIN'ов.
Правильно / логично составлена схема?
Что можно перестроить, чтобы сократить кол-во JOIN'ов?
Если вы знаете готовые варианты схем для технической поддержки - поделитесь, пожалуйста.
А почему бы не хранить заполнении тикета в Redis, а в psql сохранять уже готовый тикет?
Что вы имеете ввиду под "заполнении тикета в Redis"?
Пользователь вводит первое поле - клиентская апка срочно бежит сохранять это дело в редис. Сущностью анкеты в пг это пока не является. Кэш, всего лишь временный кэш, незаполненная инпрогресс тикета. Хранить часов 150 и хорош. Клиент прервался - вышел. Зашел снова - спрашиваем данные из хранилища. Нету - идем в поисках инпрогресс анкеты в редис. находим - вываливаем данные в апку. Пользователь продолжает заполнение. Закончил заполнение анкеты? Отправляем все на сервер, который сохраняет уже в psql. Меньше сущностей, связей и тд
Теперь понял, спасибо. Я у себя в примере не рассматриваю незаполненные тикеты. Пример - создание тикета. При создании тикета пользователь должен указать первое сообщение и приложить файлы. Предположим, что всё успешно и валидно. Что теперь нужно сделать: 1. создать запись в таблице ticket 2. создать запись в таблице ticket_message 3. создать запись в таблице ticket_message_attachmet 4. создать запись в таблице ticket_ticket_status 5. создать запись в таблице ticket_manager все действия внутри транзакции
зачем в редис? можно же просто в localStorage браузера когда все поля заполнены, тогда уже в сеть идти (редис/бд там или апи бэкенда)
Мб клиент не браузер)
1) Как часто вы хотите менять систему рейтингов и статусов? Я как-то сомневаюсь, что вы будете редактировать ticket_status, mime_type и ticket_rating через админку чаще, чем раз в год - два. 2) Почему вам нужно прямо сразу кого-то назначить на задачу? Ситуация "все операторы заняты" всё же вполне реальна. 3) Не вижу поля "вот сейчас вашей задачей занимается Петя" ) Лишние соединения можно срезать уже на стороне приложения. Например, можно пройтись по выбранным из базы сообщениям и сделать SELECT * FROM ticket_message_attachment WHERE ticket_message_id IN (<список сообщений на экране>). ticket_status, mime_type и ticket_rating включать их в JOIN смысла нет - таблицы из < 100 записей лучше целиком в память утащить один раз и использовать где надо.
Спасибо за ответ)) 1. Да, редко. Скорее всего только в самом начале. 2. Не обязательно, чтобы одному менеджеру был назначен один тикет. Можно назначить сколько угодно - для этого я и сделал промежуточную таблицу. А метка времени там для того, чтобы переназначать менеджеров на тикеты. То есть сейчас занимается тикетом тот у кого самая последняя метка времени. 3. Я думал это сделать через JOIN к таблице ticket_manager Если честно - не очень пронял про лишние соединения. Можете, пожалуйста, уточнить. Про таблицы из < 100 записей понял, спасибо. Так и сделаю.
По лишним соединениям - иногда несколько независимых SELECT будут быстрее JOIN. Например, как вы себе представляете самую жирную цепочку JOIN'ов?
Самая жирная будет при отображении пользователю его тикетов. Свой путь начинаем из талицы ticket, далее заходим в ticket_ticket_status и получаем последний статус, потом ticket_manager чтобы узнать кто занимается нашим тикетом.
Поскольку ticker_id для нас константа, я бы делал так: 1. SELECT FROM ticket_manager WHERE ticket_id [ORDER BY created_at FETCH FIRST 1 WITH TIES] 2. SELECT FROM ticket_ticket_status WHERE ticket_id 3.1. SELECT ticket_message JOIN user WHERE ticket_id, если у вас менеджер - тоже пользователь, или просто SELECT ticket_message т.к. автор заявки и так всё про себя знает. 3.2. собираете уникальные ticket_message_id из 3.1 и делаете SELECT FROM ticket_message_attachment Не знаю как вы, а я вижу только один JOIN, с ним любая база справится на счёт "раз".
Спасибо большое за ответ!
чем нарисована эта схема?
sqldbm.com (не реклама)
Обсуждают сегодня