2016-09-26 3 views
1

Справочная информация

Я создаю простой клиент чата для пользовательского веб-приложения. Я должен хранить все журналы чата. Также пользователи могут сообщать отдельным лицам или группам. Подумайте, Google Chat (который я сказал моему клиенту использовать, но он настаивал на пользовательских). Моя база данных структурирована так:Как я могу оптимизировать запрос в чате?

Таблица: Chatroom
INT Первичный ключ ChatRoomID
VARCHAR (64) Имя

Таблица ChatMessage
INT Первичный ключ ChatMessageID
int UserID
INT ChatRoomID
VARCHAR (2000) сообщение
DateTime Дата

Таблица ChatUser
INT ChatRoomID
INT Идентификатор_пользователя
INT LastMessageID Первичный ключ (ChatRoomID, Идентификатор_пользователя)

Я использую SQL Server и будет мигрирующей скоро MySQL, поэтому решение должно работать на обеих платформах.

Моя проблема

Предполагая, что пользователь только что вошли в систему Мне нужно, чтобы вытащить список всех чатов с выдающимися сообщений. Мой текущий запрос выглядит следующим образом:

 SELECT DISTINCT 
     cr.ChatRoomID AS id, 
     cu.LastMessageID AS label 
     FROM ChatRooms cr 
     LEFT JOIN ChatUsers cu ON cu.ChatRoomID = cr.ChatRoomID 
     LEFT JOIN ChatMessages cm ON cm.ChatRoomID = cr.ChatRoomID 
     WHERE cu.UserID = :user_id 
     AND cu.LastMessageID < cm.ChatMessageID 

Вопрос

Это, кажется, работает достаточно хорошо. Однако я подозреваю, что это станет неэффективным, когда их будут десятки пользователей, тысячи комнат и миллионы сообщений. Как оптимизировать этот запрос (или структуру базы данных), чтобы сделать этот запрос (количество комнат чата с выдающимися сообщениями для данного пользователя), запрос на масштабирование производительности?

Моя основная проблема заключается в том, что я вынужден использовать для этого запроса «отличный» флаг. Таким образом, это может объединить временную таблицу с миллионами до фильтрации до двух чисел.

Пример данных

Пользователи
1 | Д-р A
2 | Dr B
3 | Biller A
4 | Biller B
5 | Boss

ChatRoom
1 | Докторская группа
2 | Биллинговая группа

ChatUser
Комната | Пользователь | Сообщение
- | - | -------
1 | 1 | 0
1 | 2 | 2
1 | 5 | 2
2 | 3 | 6
2 | 4 | 0
2 | 5 | 5

Чат Сообщение
ID | Номер | Пользователь | Сообщение
- | - | - | -------
1 | 1 | 5 | «Как сегодня все?»
2 | 1 | 2 | «Я здоров. Мне нужна дополнительная помощь в комнате 5.»
3 | 2 | 5 | «Может ли кто-нибудь пополнить комнату 5 с помощью банды?»
4 | 2 | 3 | «Это не моя работа, чтобы получить лакей».
5 | 2 | 5 | «Сделайте это в любом случае или ваш уволенный».
6 | 2 | 3 | «Это твоя не твоя, и я ушел».

В этом случае пользователь 1 и 4 опоздают на работу, и когда они войдут в сообщение, появится всплывающее окно, а пользователь 5 будет удивлен в своем отделе биллинга в следующий раз, когда запустим запрос.

+0

Можете ли вы предоставить нам некоторые тестовые данные для проверки и понимания аспекта масштабируемости. – TheGameiswar

+0

И фактический индекс ddl, включая индексы. –

+0

Я не знаю, что такое ddl, и индексы должны быть очень очевидными. Я добавил примерный сценарий. – danielson317

ответ

4

Вы можете оптимизировать этот запрос следующим образом:

select cr.ChatRoomID AS id, 
    cu.LastMessageID AS label 
from ChatUsers cu inner join ChatRooms cr ON cu.ChatRoomID = cr.ChatRoomID 
where cu.UserID = :user_id and 
exists (select 1 from ChatMessages cm where cm.ChatRoomID = cr.ChatRoomID and cu.LastMessageID < cm.ChatMessageID); 

Есть в основном 2 проблемы с текущим запросом:

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

Это что-то подобное мы решили на https://www.applozic.com.

Отказ от ответственности: Я работаю над Applozic.

+0

Это, кажется, устраняет массивное соединение, которое является таблицей сообщений. Но не выполняется ли запрос sub для каждого результата запроса на обертку? Я чувствую, что это может создать аналогичную проблему. – danielson317

+1

Таким образом, всякий раз, когда извлекается первая запись, запрос останавливается и запускается для другого. Другой способ оптимизировать это - сохранить метку времени сообщения в таблице ChatUser всякий раз, когда отправляется новое сообщение, и проверять метку времени LastMessageId на сохраненную метку времени. –

Смежные вопросы