Делаю чат между пользователями и в качестве СУБД выбрал MySQL.
Имеются две таблицы: users, messages.
Пользователей в списке контактов нужно сортировать по дате последнего сообщения.
Тут два варианта: джоинить таблицу messages и брать дату последнего сообщения или завести поле last_message_time в users и сортировать по нему. Второй вариант кажется более правильным, но в этом случае при каждом сообщении нужно будет делать update.
Хорошая ли это идея? На сколько update поля без индекса ресурсоемкий в MySQL?
WebDev, Это пять ясчитаю. То есть если понадобится загрузить последние 50 сообщений вы вытаскиваете все 5000(условно) строк, пакуете в json, отправляете на клиент и там яваскриптом сортируете? Нааайс.
ThunderCat, Это чат с техроддержкой. Предполагается, что человек пришел на сайт, задал пару вопросов и все. То есть с десяток сообщений. Но в целом вы правы конечно. Подскажите, как лучше сделать?
WebDev, не ломать себе голову и делать нормальный джоин, или делать запрос с in() и внутри in выбирать идентификаторы с сортировкой по дате из нужной таблицы с нужными условиями. Обычно это очень быстро работает.
WebDev, в идеале должна быть таблица с полями user_id, last_message_id (если нужно будет вывести последнее сообщение в списке или другую информацию), last_message_time с уникальным индексом на поле user_id и обычным индексом на поле last_message_time (можно задать сортировку для индекса). Имея такую таблицу, можно максимально быстро сделать описанную в вопросе выборку.
Идея на троечку с минусом.
Во первых нарушает 3 нормальную форму,
во вторых требует модификации сторонних "чистых" сущностей, размазывая логику
в третьих - если у человека 10 диалогов - какой из них вы будете писать в МОЙ лист верхним?
Сергей Семенко, Это не тот случай, денормализация нужна там где это оправдано, например, размерами таблиц, при джоине которых образуются пересечения на пару миллионов строк и никаких явно ограничивающих условий. Здесь этого нет, а просто ляпнуть что есть такая штука я и сам могу.
ThunderCat, про размер таблиц ничего не сказано. В любом случае нежелательно использовать сортировку по полям из другой таблицы. Тем более в данном случае нужно определить дату последнего сообщения для каждого из пользователей.
Сергей Семенко, список контактов у вас как формируется? Есть поля связи оператор-клиент? Если есть значит выборка ограниченная связью, а не фуллскан, плюс у вас есть лимит (допустим 20-30 последних диалогов). То есть реально у вас джоин 20 строк на пофиг сколько, так как по индексу. Если нет, значит на этапе проектирования бд что-то сильно пошло не так.
PS: Не вам напрямую ответ, но принцип такой именно.
ThunderCat, чтобы получить 20 последних диалогов, их сначала нужно отсортировать, значит join будет для всех записей. Но даже если выборка будет ограничена, скорость выполнения запроса будет зависеть от этих ограничений.
Мне кажется в этом случае можно вести отдельную таблицу с user_id (uniq index) и временем последнего сообщения. При отправке сообщения выполнять REPLACE по идентификатору пользователя + текущее время.
чтобы получить 20 последних диалогов, их сначала нужно отсортировать, значит join будет для всех записей.
Для всех записей, удовлетворяющих связке, а это уже сильное условие. И оттуда сорт и лимит 20 будет по индексу. И только потом джоин. Фактически это 2 запроса - выборка 20 значений из 1 таблицы (или из двух, зависит от структуры данных), потом селект из другой с данными из первого селекта в условии ограничения.
ThunderCat, если поле для сортировки находится в другой таблице, то для получения первых 20-ти записей нужно сначала сделать join, отсортировать и только потом взять первые 20 записей. В такой схеме мы сильно зависим от размера join таблицы. Единственный способ оптимизировать такой запрос - поднять поле для сортировки наверх. Или я что-то не понял?