Структура хранения сообщений чата в базе данных [закрыт]
Закрыт. На этот вопрос невозможно дать объективный ответ. Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах.
Закрыт 7 лет назад .
Собственно, вопрос навеян другим вопросом. Заключается в следующем. Какой оптимальный способ хранения сообщений чата? Может быть лучше их сохранять вообще просто в файл (ведь обращение к старым практически исключено, а вычитка последних может идти и из оперативной памяти)? Или может быть лучше (как в упомянутом вопросе) рассматривать хранение сообщений в базе в виде JSON-строк за определенный период времени? А может все-таки лучше их хранить в базе в виде «одно сообщение — одна строка» и при этом все данные расположены по полям? Какие еще есть варианты? Какие у этих вариантов (и других) плюсы и минусы?
Отслеживать
задан 25 июл 2016 в 20:38
user212277 user212277
Если вам дан исчерпывающий ответ, отметьте его как верный (галочка напротив выбранного ответа)
25 июл 2016 в 21:34
@Mihanik71 Несомненно, так и поступлю. Но не ранее, чем отвечающие начнут читать вопрос и отвечать по существу вопроса.
– user212277
26 июл 2016 в 8:06
Укажите какими средствами делается серверная часть. И какую БД вы имеете ввиду. Если реляционную — отдельная строка на сообщение, без вариантов. Если документарную или около того — то видимо JSON или как там она документ хранит. С файлами — в определенных случаях можно сделать оптимально, но объем работы на пару порядков выше.
26 июл 2016 в 8:21
@Mike Прочитайте вопрос. Ведь черным по белому написано: как лучше хранить сообщения чата? Может лучше вообще без базы? Причем здесь Ваши комментарии по поводу базы данных? Причем здесь непосредственно JSON, если я в вопросе написал, что это как вариант, а как другой вариант — традиционное сохранение в базе по строкам и полям. Какая разница при этом какими средствами делается серверная часть? Есть средства, которые позволят ее сделать, но не позволят использовать базу данных или файловую систему?
– user212277
26 июл 2016 в 8:28
Очень хотелось бы уточнить у тех, кто требует правки, как можно отредактировать простой вопрос:Какой оптимальный способ хранения сообщений чата?И да.Ну очень много ответов может быть основано сугубо на чьем-то мнении. Вот их бы и хотелось услышать. Но услышать мнения по существу вопроса, а не ответы о том, как данные из базы будут потом плохо читаться.В вопросе указано, что это чат (не мессенджер) и читаться сообщения не будут.Ответов по существу нет, несмотря на разжеванный вопрос?Как, уважаемые, господа-товарищи вы предлагаете его переформулировать?Может прочтете его внимательно для начала?
– user212277
26 июл 2016 в 8:55
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Хранение в JSON данных за день/месяц/год:
+Легко отдавать данные за период
-Отсутствует возможность поиска
-Увеличение размера хранимых данных
-Большой объём передаваемых данных
-Усложнение системы хранения данных (сначала нужно хранить где то данные за период, потом переносить в базу)
Хранение в файлах данных за день/месяц/год:
+Легко отдавать данные за период
-Отсутствует возможность поиска
-Увеличение размера хранимых данных
-Большой объём передаваемых данных
-Усложнение системы хранения данных (сначала нужно хранить где то данные за период, потом переносить в файл)
Хранение в базе:
+Легко отдавать данные за период
+Стандартные возможность поиска
+Передаём только нужные данные
-Хранятся актуальные и старые сообщения
В лучшую сторону ничего не изменится если Вы будете хранить сообщения в JSON.
- Места занимает столько же, а то и больше.
- Теряется возможность запросов. Нельзя будет сделать сложных запросов.
- Передавать данные сложнее. (Кто то очень активный наобщается на 10 метров и будете Вы на клиент их передавать).
Хранить в файлах историю по дням можно, но тоже не особо что то поменяет.
Вы боитесь что если у Вас будет несколько миллионов записей, то у Вас скорость запросов упадёт при обычном селекте? Это не так доступ же линейный.
А по всему остальному в чём разница — хранить в базе или в файлах? Что то что то место занимает.
Лучше чем просто в базе ещё вроде не придумали.
Как правильно хранить переписку в БД в данном случае?
Пишу проект на java. В качестве СУБД выбрал mySql. Возникла потребность в хранении переписки между пользователями. В программе присутствует только диалог 1:1 никаких комнат и ничего подобного. Я думаю правильно хранить полностью всю переписку в одной таблице, но как правильно это реализовать? Плюс мне нужно как-то формировать историю сообщений. Из идей у меня такое:
|логин_отправителя|логин_получателя|текст_сообщения|дополнительный_параметр_сообщения|номер_предыдущего_сообщения| .
Но вот мне не нравится такая конструкция по причине, что , чтобы добавить новое сообщение, мне нужно знать номер предыдущего. И вдруг пользователи в раз отправят сообщение, и что получится? что два сообщения под одним номером? Как вообще тогда формировать смс? Правильно ли я составил таблицу?
- Вопрос задан более трёх лет назад
- 767 просмотров
Комментировать
Решения вопроса 3

Здесь отвечаю на вопросы.
Без дополнительной таблицы. В таблице сообщений хватит Код, кто, кому, время , что бы выбрать переписку.
не буду знать какое смс пришло раньше
То, у которого код меньше, если у вас точности время не хватает.
Ответ написан более трёх лет назад
Нравится 1 1 комментарий
TopMetaFizick_010 @TopMetaFizick_010 Автор вопроса
У каждого пользователя свой connectoion к бд, что произойдет если они в раз напишут друг-другу? В бд получится одно и тоже время? Если так, то как я буду формировать истроию переписки, порядок смс может перепутаться, т.к. я не буду знать какое смс пришло раньше? или я не прав?

Рецепты https://codepen.io/jrkdv/full/LKLXdq
user = id | .
message = id | user_id | timestamp | msg | .
История чата:
SELECT msg FROM message WHERE user_id=uid1 OR user_id=uid2 ORDER BY timestamp;
где uid1\uid2 собеседники
при одинаковом времени, всё равно одна запись будет раньше, другая позже
Ответ написан более трёх лет назад
Нравится 1 1 комментарий
TopMetaFizick_010 @TopMetaFizick_010 Автор вопроса
Либо я не так понял, либо тут мы получаем только исходящие смс от uid1?
И у пользователя же может быть хоть какое количество диалогов. Как узнать сколько у него диалогов и с кем они? Пробегаться по всей таблице, и смотреть сколько уникальных uid2 у пользователя uid1?
Таблица такая: Messages(id, user_from_id, user_to_id, text, msg_time, . ).
Никаких предыдущих номеров Вам запоминать не нужно и никаких записей с одинаковым номером не будет. В таблице Messages поле id делаете автоинкрементным и забываете обо всем, что вас беспокоит.
Как получать историю:
select * from Messages where user_from_id = $id_пользователя or user_to_id = $id_пользователя order by id
Ответ написан более трёх лет назад
TopMetaFizick_010 @TopMetaFizick_010 Автор вопроса
Опять же, разве я не получаю таким способом только исходящие смс? Если входящие в бд записаны немного наоборот, т.е. user_from_id и user_to_id поменяны местами? Не бейте палкой, я просто новичок в этом деле, и с БД знаком очень поверхностно, да, знаю, что нужно изучить принцип работы, но пока на изучении стоят совсем другие технологии, а БД нужно просто привинтить к проекту для более менее стабильной работы.
TopMetaFizick_010, нет, таким образом вы получаете всю историю сообщений для какого-то пользователя. Допустим есть пользователь Вася и его И допустим он написал Диме у которого сообщение. Тогда в таблицу попадает запись, где user_from_id=52(кто отправил — Вася), а user_to_id=105(кому отправили — Диме). А если Дима напишет Васе то запись будет выглядеть наоборот — user_from_id=105(кто отправил — Дима), а user_to_id=52(кому отправили — Васе). Так вот запрос, который я привел выше — если Вы в него подставите id Васи то есть 52, то он вернет все сообщения, где встречается среди отправителей(«user_from_id = $id_пользователя») и все сообщения, где встречается среди получателей(«user_to_id = $id_пользователя»), то есть вернет всю историю сообщений Васи
БД для хранения сообщений чата, какую выбрать?
Добрый день, делаю проект на Yii2, в нем уже реализован чат на комет сервере чат уже полностью работает, пользователи могут общаться только в приватных беседах т.е. только 2 пользователя друг с другом. При отправке сообщения, оно улетает аяксом в php скрипт, валидируется по определенным правилам и если все ок, записывает в таблицу бд и возвращает успех на клиентскую часть после чего уже сообщение попадает в окошко чата.
Структура бд:
tbl_dialog:
dialog_id — id Диалога
dialog_one_user_id — id первого юзера
dialog_two_user_id — id второго юзера
dialog_time — время создания диалога
tbl_message
chat_messages_id — id сообщения
chat_messages_text — текст сообщения
chat_messages_fk_dialog_id — id Диалога к которому относится сообщение
chat_messages_fk_user_id — id отправителя
chat_messages_fk_to_user_id — id получателя
chat_messages_ip — ip отправителя
chat_messages_isRead — прочитано ли сообщение получателем
chat_messages_isVisible_one_user — видимость сообщение для первого юзера
chat_messages_isVisible_two_user — видимость сообщение для первого юзера (для возможности отчисти сообщений, если просто удалять тогда сообщение пропадет из истории у обоих юзеров)
chat_messages_time — время отправки сообщения
Вся система работает с бд MySQL — InnoDB, сообщения пишутся в бд при каждой отправке (INSERT), пока сервис еще не запущен, сообщений мало (только мои тестовые) все работает шустро, но вот когда запущу и количество сообщений перевалит за несколько миллионов, что будет тогда с моей бд? Начнутся жесткие тормоза при select и insert?
Вот пока не поздно думаю стоит ли переписывать хранение сообщений на другую NoSQL БД, с ними не работал никогда, почитал доки и на первый взгляд ничего сложного.
В голове вертятся 2 варианта реализации:
1) перевести табличку tbl_message в коллекцию MongoDB и так же писать туда сообщения при каждой отправке (т.е. пользователь отправил 1 сообщение и мы его сразу в бд записали, по одной записи делать буду и так каждое сообщение). Как Mongo будет вести себя при вставке сообщения, когда в коллекции будет за 20 млн записей? Правильная ли эта схема?
1) Записывать каждое сообщение в память в виде массива сообщений (memcached или redis или еще что то — посоветуйте) и по крону допустим каждую минуту или 5 мин брать весь массив сообщений, писать через транзакцию в MySQL, далее чистим массив сообщений для новых записей. Так получается что не будет несколько инсертов в секунду, т.к. сообщения будут храниться в памяти. Но тут опять засада, сможет ли MySQL нормально работать с огромной таблицей 20млн записей?
Сам текст сообщений очень короткий, что то типа «Привет! Как дела?»
- Вопрос задан более трёх лет назад
- 18076 просмотров
3 комментария
Средний 3 комментария
Система личных сообщений
Подскажите, пожалуйста, как устроена система личных сообщений между пользователями в крупных проектах (Вконтакте, Одноклассники, Topface и т.п) с учетом масштабирования? Интересует именно хранение данных о пользователях/чатах/сообщениях и доступ к этим данным.
Допустим у нас есть 100 000 000 пользователей и необходимо сделать горизонтальное масштабирование (шардинг) этих данных на 200 MySQL серверов. На данный момент, я вижу это следующим образом: разделяем всех пользователей и данные на 200 серверов по user_id, получается примерно 500 000 юзеров на каждый сервер. Можно еще разделить данные на споты по 1000 юзеров и получится, что на каждом сервере БД будет 500 спотов по 1000 юзеров (всего 500 000 юзеров на сервер).
Доступ к серверам БД/спотам можно вычислять по user_id, например spot_id = user_id % 1000. Каждый спот будет хранить данные в виде таблиц, например:
Spot1: — spot1_users (информация о пользователях) — spot1_chats (информация о чатах между пользователями) — spot1_messages (сообщения из чатов) .
Spot2: — spot2_users — spot2_chats — spot2_messages . Проблема возникает тогда, когда необходимо хранить/получать общие данные между юзерами. Например, 2 пользователя начинают переписку между собой. В этом случае необходимо создать чат в таблице spotN_chats и поместить туда информацию chat_id (id чата), receiver_id(id получателя), sender_id (id отправителя). Сообщения будут хранится в таблице messages (chat_id, message, time).
Теперь начинается самое интересное — пользователи начинают переписку между собой. Здесь необходимо сделать такие базовые операции: 1) Создание нового чата между 2 пользователями 2) Получение информации о чате или списке чатов конкретного пользователя 3) Создание нового сообщения 4) Получение списка сообщений по chat_id
Также есть 2 варианта развития событий: 1) пользователи находятся на одном споте (например, spot1); 2) пользователи находятся на разных спотах (например, spot1 и spot2);
Задача 1. Пользователь1 решил начать переписку с пользователем2. В этом случае необходимо создать новый чат в БД. Если пользователи на одном споте, то можно просто создать новый чат в таблице spot1_chats, получать chat_id, а дальше создавать новые сообщения в таблице spot1_messages с полученным chat_id. Но если пользователи находятся на разных спотах (spot1, spot2), то такой подход не будет работать, поскольку чтобы каждый пользователь увидел список своих чатов, то их нужно дублировать на 2 споты одновременно. Но в таком случае chat_id будут разными для 2 таблиц(spot1_chats, spot2_chats) если использовать поле autoincrement для chat или же нужно строить какой-нибудь общий для 100 млн. пользователей генератор id для новых чатов. Кроме того, если 2 пользователи на одном споте, то при дублировании чатов все равно будет создан только 1 чат в таблице spot1_users, а вот если мы решим перенести 1 пользователя на другой спот, то как дублировать информацию о чатах?
Задача 2. Пользователь1 отправляет сообщение пользователю2, chat_id у нас уже есть после создания нового чата. Здесь возникает та же самая проблема, что и в первой задаче. Если 2 пользователи на одном споте, то мы просто добавляем новое сообщение в таблицу spot1_messages, но если в будущем захотим перенести пользователя на другой спот, то как дублировать сообщения? Если же пользователи на разных спотах, то для отправки сообщения необходимо создать новое сообщение в таблице spot1_messages и в таблице spot2_messages. Кроме того, если мы хотим обновлять какой-нибудь счетчик новых сообщений или время последнего сообщения в чатах, то нужно будет также обновлять информацию о чатах в таблицах spot1_chats и spot2_chats. Получается для простой отправки одного сообщения необходимо будет сделать несколько запросов в БД, а именно: создать новое сообщения в таблицах spot1_messages и spot2_messages, а также обновить информацию о чате в таблицах spot1_chats и spot2_chats.
Подскажите, пожалуйта, как правильно решить данные задачи или возможно есть какой-то другой более простой/надежный способ хранения сообщений из реального опыта.