简体   繁体   English

加入4个表的MYSQL查询优化

[英]MYSQL query optimization joining 4 tables

Need help to optimize this query 需要帮助来优化此查询

The task is to select my friends from friends table, to check if any of them is in ignore table, to get their info from users table, also to get the last message date from messages table. 任务是从friends表中选择我的朋友,检查他们中的任何一个是否在忽略表中,从用户表中获取他们的信息,也从消息表中获取最后的消息日期。 My friends also can be group's. 我的朋友们也可以成为团体的。

My query: 我的查询:

SELECT
        `u`.`id`, `u`.`login`, `u`.`name`, `u`.`surname`,
        CONCAT(`u`.`name`, ' ', `u`.`surname`) AS `namesurname`, `u`.`avatar`,
        `u`.`status`, `u`.`status_text`, `u`.`last_active`, `u`.`type`,
        `f`.`status` AS `friend_state`, `i`.`date` AS `ignore_date`,
        MAX(`m`.`date`) AS `last_message_date` 
    FROM `friends` AS f 
    INNER JOIN `users` AS u ON `u`.`id`=`f`.`friend_id`
    LEFT JOIN `ignore` AS `i` ON `i`.`uid`='10' AND `i`.`ignore_id`=`f`.`friend_id`
    LEFT JOIN `messages` AS `m` ON `m`.`date`>DATE_ADD(NOW(), INTERVAL -1 DAY) AND 
    (
        (`m`.`fromid`=`u`.`id` AND `m`.`toid`='10') OR 
        (`m`.`toid`=`u`.`id` AND `m`.`fromid`='10') OR
        (`m`.`toid`=`u`.`id` AND `m`.`toid` IN (16,22,27))
    ) 
    WHERE `f`.`uid`='10'
    GROUP BY `u`.`id`
    ORDER BY `last_message_date` DESC, `namesurname`

For 170k messages this query tooks 2.2-2.5 seconds. 对于170k消息,此查询花费了2.2-2.5秒。

if I remove 如果我删除

(`m`.`toid`=`u`.`id` AND `m`.`toid` IN (16,22,27))

the it tooks 0.55 seconds 花了0.55秒

10 - is my users ID 10 - 是我的用户ID

16,22,27 - id of groups 16,22,27 - 群组的ID

I need this line ( m . toid = u . id AND m . toid IN (16,22,27)) because in group chats it shouldn't depend on who sent the last message. 我需要这条线( mtoid = uid AND mtoid IN(16,22,27)),因为群聊不应该取决于谁发送的最后一条消息。

Thanks in advance 提前致谢

You probably don't need LEFT . 你可能不需要LEFT Assuming that, I would turn the ORs into UNIONs and start with such: 假设,我会将ORs转换为UNIONs这样开始

Since you have not provided SHOW CREATE TABLE , I will guess that messages has PRIMARY KEY(mid) . 由于您还没有提供SHOW CREATE TABLE ,我猜测messagesPRIMARY KEY(mid)

SELECT ...
    FROM ( ( SELECT mid FROM messages WHERE fromid = u.id AND toid = 10 )
           UNION ALL 
           ( SELECT mid FROM messages WHERE toid = u.id AND fromid = 10 )
           UNION ALL 
           ( SELECT mid FROM messages WHERE toid = u.id AND toid IN (16,22,27) ) AS um
    JOIN users AS u  ON ...
    JOIN 

Oops, instead I will approach it from trying to do as much as possible in messages first, assuming the 1-day limitation is a significant filter. 糟糕,相反,我会先尝试尽可能多地在messages ,假设1天限制是一个重要的过滤器。 (Notice how an estimated 170K rows need to be scanned.) (注意估计需要扫描170K行。)

Start by checking this to see if it is 'fast' and delivers not 'too many' rows: 首先检查一下它是否“快速”并且不是“太多”行:

SELECT COUNT(*) FROM (
        ( SELECT toid AS either_id, MAX(date) AS last_date FROM messages
             WHERE toid IN (10, 16,22,27) AND date > NOW() + INTERVAL 1 DAY )
        UNION ALL   -- or, if you get dups, UNION ALL
        ( SELECT fromid, MAX(date) FROM messages
             WHERE fromid = 10 AND date > NOW() + INTERVAL 1 DAY )
                     ) um;

Assuming that is OK, then work on 假设没问题,那就继续吧

SELECT ...
    FROM ( ... ) AS um   -- the derived table above
    JOIN users AS u  ON um.either_id = u.id
    JOIN ...   -- the rest of the stuff

Indexes... 索引...

messages:  (toid, date)
messages:  (fromid, date)

(It's a really messy query, so I don't have confidence that I have helped.) (这是一个非常混乱的查询,所以我对自己的帮助没有信心。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM