У меня есть таблицы ChatMessages
, ChatGroups
и ChatGroupMemberships
. Пользователь может быть в 0..N группах и в группе может быть 1..N сообщений чата. Это первое сообщение создается после того, как группа инициирована, и это своего рода «живой» пинг.
Я оптимизирую способ восстановления списка разговоров пользователя. Этот список довольно стандартен, и вы можете знать его по любому социальному сайту:
| Chat with User X -> [last message in that chat group]
| Group chat named ABC -> [same]
До сих пор я делал то, что просто запрашивал список ChatGroupMemberships
, где userId = X
(x при входе в систему пользователя ), а затем для каждой записи в этой коллекции я выбрал последнее сообщение в этой группе, а затем упорядочил весь список на сервере (это нужно сделать в БД).
Я создаю запросы с помощью NHibernate, где это возможно, в этом проекте, поэтому следует выполнить следующую функцию:
public ChatMessage GetLastMessageInGroup(int groupId)
{
return session.CreateCriteria<ChatMessage>()
.AddOrder(Order.Desc("Date"))
.Add(Restrictions.Eq("RecipientId", groupId))
.SetMaxResults(1)
.List<ChatMessage>().FirstOrDefault();
}
Теперь я почти уверен, что это довольно уродливое решение, которое я сделал там и по мере того, как пользователи создавали все больше и больше чат-групп, время восстановления этого списка разговоров начинало занимать все больше и больше времени (я делаю это через AJAX, но все же). Сейчас пользователь обычно состоит из около 50 групп.
Таким образом, возникла необходимость оптимизировать этот процесс, и сейчас я делаю то, что я хотел бы разделить загрузку этого списка на меньшие партии. По мере прокрутки список пользователей загружает записи на лету.
Функция, над которой я работаю, выглядит следующим образом:
public List<ChatGroupMembershipTimestamp> GetMembershipsWhereUserId(int userId, int take, int skip)
{
}
Я провел несколько часов, изучая CTE, и придумал следующее:
WITH ChatGroupMemberships AS
(
SELECT p.Date, p.RecipientId, p.RecipientType, p.Id, p.userId
ROW_NUMBER() OVER(PARTITION BY p.RecipientId, p.userId ORDER BY p.Id DESC)
AS rk FROM ChatMessages p
)
SELECT s.date, s.recipientId as groupId, s.recipientType as groupType, s.userId
FROM ChatGroupMemberships s
WHERE s.rk = 1
Order by s.date desc;
Возвращает последнее (новейшее) сообщение для каждого пользователя в каждой группе. Подвох в том, что мой пользователь не входит в каждую из этих групп, поэтому мне нужно каким-то образом присоединиться? в таблице ChatGroupMemberships
и проверить, есть ли строка с идентификатором этого пользователя как userId
Ниже приведен пример запроса:
![enter image description here](https://i.stack.imgur.com/5pBLV.png)
Возможно, я слишком усложнил это, мой первоначальный план состоял в следующем:
select m.id as messageId, groupId, date
from ChatGroupMemberships g
join ChatMessages m on g.groupId = m.recipientId
where g.userId = XXX <-- user's id
order by m.date desc
Выход:
![img2](https://i.stack.imgur.com/bwNrn.png)
Но здесь мне понадобится только самая верхняя строка для каждого идентификатора группы, который я пробовал делать с запросом выше. Извините, это может сбить с толку (из-за отсутствия у меня правильных терминов / знаний), и это довольно длинный вопрос.
Если понадобится какое-либо разъяснение, я был бы более чем рад сотрудничеству.
Наконец, я прилагаю схемы оформления таблиц
сообщения чата:
![chat messages](https://i.stack.imgur.com/1YYMB.png)
членство в группах чата:
![enter image description here](https://i.stack.imgur.com/fzlr0.png)
группы чата:
![enter image description here](https://i.stack.imgur.com/eg9KW.png)