使用更好的MySQL查询对最后消息进行分组

时间:2018-02-07 13:45:50

标签: mysql sql

我试图显示所有最后消息的列表,类似于当您查看所有消息时显示在Facebook上的消息(并显示最后消息和消息的消息)。

我的表格如下:

id | userid | fromuserid | touserid | message | time
 1 |   1    |     1      |    2     |  test1  | 1428882596
 2 |   2    |     1      |    2     |  test1  | 1428882596
 3 |   2    |     2      |    1     |  test2  | 1428882600
 4 |   1    |     2      |    1     |  test2  | 1428882600

userid在那里是因为邮件是重复的(每个用户都有他/她自己的邮件副本,所以他们可以删除它们,也因为它们可以存储的最大邮件数限制。)

这是我的疑问:

   SELECT messages.*
        , users.username
        , users.firstname
        , users.lastname
     FROM messages
LEFT JOIN users ON ( users.id            = messages.fromuserid
                     AND messages.touserid   = '$userid' )
                OR ( users.id            = messages.touserid
                     AND messages.fromuserid = '$userid' )
    WHERE messages.id IN ( SELECT MAX(id)
                             FROM messages
                            WHERE userid = '$userid'
                            GROUP BY GREATEST(fromuserid, touserid)
                                     , LEAST(fromuserid, touserid) )
    ORDER BY messages.time DESC 

查询有效,但速度非常慢(执行时间约为0.1 - 0.2秒,表格大约有8000个条目)。我也设置了索引,只是查询速度很慢。

有没有人知道更好的方法来做到这一点,而无需创建额外的表来存储最后的消息?无论我尝试了多少,我总是最终想到我需要创建一个额外的表,如果可能的话我想避免使用。

编辑:我知道文本复制是一个坏主意(我将为此创建一个单独的表),我的问题只是分组和显示最后的消息,如果可以在没有额外的表的情况下完成

非常感谢!

2 个答案:

答案 0 :(得分:2)

如果您关心性能,有时最好使用flag处理复杂查询(我们在表中添加了额外的列)

1-在消息表中添加一列,将其命名为isLast,将默认值设为1

2-创建一个触发器before insert更新消息中属于当前用户的每一个旧行(我假设您可以使用NEW.touserid或NEW.fromuserid获取它), SET isLast = 0

3 - 然后在与用户加入消息时,您只需要在条件中检查isLast > 0(不再有子查询)

答案 1 :(得分:0)

你想要尽可能多的表(在合理范围内)。

第一条规则,关联,不要复制!

如果可以,

也会为列编制索引。

CREATE FULLTEXT INDEX idx ON `messages`(`message`);

在基于文本的列(CHAR,VARCHAR或TEXT列)上创建FULLTEXT索引,以帮助加快对这些列中包含的数据的查询和DML操作,省略任何定义为停用词的单词。

FULLTEXT索引定义为CREATE TABLE语句的一部分,或使用ALTER TABLE或CREATE INDEX添加到现有表中。

https://www.ntu.edu.sg/home/ehchua/programming/sql/Relational_Database_Design.html