Как вам такой MySQL запрос? Не будет ли она сильно нагружать БД? Как его можно оптимизировать? Код (Text): SELECT D.id,sender_id,recipient_id,send_notifications, S.id AS sender_id, R.id AS recipient_id, R.name AS recipient_name, R.birthday AS recipient_birthday, R.status AS recipient_status, R.sex AS recipient_sex, R.last_activity_at AS recipient_last_activity_at, BS.id AS im_blakcklist, BR.id AS youare_blakcklist, LM.id AS last_message FROM dialogs D JOIN users S on S.id=IF(93=sender_id, sender_id, recipient_id) JOIN users R on R.id=IF(93=recipient_id, sender_id, recipient_id) LEFT JOIN blacklist BS on BS.uid=S.id and BS.who=R.id LEFT JOIN blacklist BR on BR.uid=R.id and BR.who=S.id WHERE ((sender_id=93 and recipient_id!=93) or (sender_id!=93 and recipient_id=93)) ORDER BY id DESC LIMIT 0,16 Там где 93, будет передаваться ID текущего пользователя
да почти никак. условие OR не дружит с индексами. мне кажется, здесь два раза лишнее условие с != ибо незачем скрывать от пользователя переписку с самим собой ))) она вообще есть? но я не думаю, что упрощение до (sender_id=93 or recipient_id=93) радикально улучшит скорость. можешь попытаться заменить его на UNION или UNION ALL Код (Text): SELECT blablabla... JOIN tyctyctyc WHERE sender_id=:ID UNION ALL SELECT blablabla... JOIN tyctyctyc WHERE recipient_id=:ID это выглядит хуже, чем работает попробуй и сравни --- Добавлено --- P.S. предполагаю, что у тебя есть индексы по sender_id и recipient_id
Я, чтоб не делать такие запросы, храню сообщения отдельно. У меня таблицы dialogs, messages, dialog_user. dialog_user - это, соответственно, связующая таблица для "многие-ко-многим", а в messages есть только from_id, recipient_id не нужен. В результате я делаю простую выборку по messages, и всё. Когда-то у меня получился подобный запрос, когда я начал как @artmirartem решать эту задачу, я ему ужаснулся, и решил переделать архитектуру. Пришёл к этому решению, и очень доволен. Уже на нескольких проектах проверено.
Код (Text): select du.dialog_id from dialog_user du join dialog_user du2 on du2.dialog_id=du.dialog_id where du.user_id=1 and du2.user_id=4; Как-то так. Свой код прямо сейчас лень поднимать. --- Добавлено --- Самое крутое в моём решении, что оно подходит и для чатов с большим количеством участников.
Список диалогов в таком случае для каждого пользователя можно получить так: Код (Text): SELECT dialog_id, DU.uid AS sender_id FROM fdy82_dialogs_users DU LEFT JOIN fdy82_dialogs D ON D.id=DU.dialog_id WHERE DU.uid=93 ORDER BY D.id DESC LIMIT 0,16 Но как тогда получить имя пользователя и аватар, КОТОРОМУ адресовано сообщение. В списке диалогов у каждого пользователя эту информацию тоже мне нужно выводить.. --- Добавлено --- в моем запросе (самом первом) я делал это с помощью JOIN'ов, и у меня заранее был известен получатель и отправитель
Не понял вопроса. У тебя диалог между двумя пользователями, которые заранее известны, так? Если один из них отправитель, то другой - получатель. На этом и основано моё решение не хранить получателя в messages, а хранить только id диалгога. А если речь идёт о последнем сообщении, то можно ввести поле last_message_id в таблицу dialogs, и подновлять его. Но твой проект, тебе решать. Я тебе это привёл не для того, чтобы сказать, что моё решение самое лучшее. Для меня это так, поскольку я получаю сообщения совсем элементарным select-ом. И остальное в принципе тоже не самыми сложными запросами. Иконку получателя правда мне ни разу не приходилось выводить, обычно идёт иконка отправителя.
нет, заранее неизвестно, но мне нужно вытащить из БД все диалоги у текущего пользователя и вмест с диалогами вытащить имя и аватраку другого пользоателя в этом же лдиалоге
Ну я могу код Laravel показать. У меня все эти проекты на Laravel PHP: $models = Dialog::query() ->withParticipant($user) ->with("users") ->with("lastMessage") ->orderByDesc("last_message_date") ->get(); PHP: class Dialog extends Model { use ReadCountable; protected $casts = [ 'deleted' => 'array', ]; public function messages() { return $this->hasMany(Message::class); } public function users() { return $this->belongsToMany(User::class); } public function lastMessage() { return $this->hasOne(Message::class, "id", "last_message_id"); } public function scopeWithParticipant(Builder $builder, $participant) { return $builder->join("dialog_user as du", "dialogs.id", "=", "du.dialog_id") ->where("du.user_id", $participant instanceof User ? $participant->id: $participant) ->where("du.hidden", 0); } } Т.е. соответственно, некоторые вещи делаются в два запроса. Ну один или два запроса - для меня непринципиально. Много раз убеждался, что один или два на время выполнения заметным образом не влияет, влияет разница в десятки раз. --- Добавлено --- Можно и в один запрос нагородить, в принципе, если самому запросы все писать, не использовать Eloquent. Но я использую.
Вот такой у меня запросик получился Код (Text): SELECT D.id,D.send_notifications, S.id AS sender_id, R.id AS recipient_id, R.name AS recipient_name, R.birthday AS recipient_birthday, R.status AS recipient_status, R.sex AS recipient_sex, R.last_activity_at AS recipient_last_activity_at, BS.id AS im_blakcklist, BR.id AS youare_blakcklist, PS.path as recipient_avatar FROM dialogs_users DU_S LEFT JOIN dialogs_users DU_R ON DU_R.dialog_id=DU_S.dialog_id LEFT JOIN dialogs D ON D.id=DU_S.dialog_id JOIN users S ON S.id=DU_S.uid JOIN users R ON R.id=DU_R.uid LEFT JOIN photos PS on PS.uid=S.id and PS.avatar=1 LEFT JOIN photos PR on PR.uid=R.id and PR.avatar=1 LEFT JOIN blacklist BS on BS.uid=S.id and BS.who=R.id LEFT JOIN blacklist BR on BR.uid=R.id and BR.who=S.id WHERE DU_S.uid=93 and DU_R.uid!=93 ORDER BY D.id DESC LIMIT 0,16
Оставлю здесь ссылочку на свой старый ответ по близкой теме: https://php.ru/forum/threads/sistema-soobschenij.57436/#post-462055 в тот момент писалось на лету, не проверяя запросы, так что безошибочность не гарантирую )))