选择需要8秒改进想法

brccelvz  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(390)

我有这个选择来获得聊天(像facebook收件箱)。它将显示最近的消息,按发送它们的用户分组。

SELECT c.id, c.from, c.to, c.sent, c.message, c.recd FROM chat c 
WHERE c.id IN(
  SELECT MAX(id) FROM chat
  WHERE (`to` = 1 and `del_to_status` = '0') or (`from` = 1 and `del_from_status` = '0')
  GROUP BY CASE WHEN 1 = `to` THEN `from` ELSE `to` END
)
ORDER BY id DESC
limit 60

问题是大约需要8秒钟。

`chat` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `from` int(11) UNSIGNED NOT NULL,
  `to` int(11) UNSIGNED NOT NULL,
  `message` text NOT NULL,
  `sent` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `recd` tinyint(1) NOT NULL DEFAULT '0',
  `del_from_status` tinyint(1) NOT NULL DEFAULT '0',
  `del_to_status` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `from` (`from`),
  KEY `to` (`to`),
  FOREIGN KEY (`from`) REFERENCES cadastro (`id`),
  FOREIGN KEY (`to`) REFERENCES cadastro (`id`)
)


有没有办法索引或重新编写这个选择,以获得更好的速度?

bgibtngc

bgibtngc1#

我假设是专栏 id 已经索引,因为它可能是表的主键。如果不是这样,请添加索引:

create index ix1_chat on chat (id);

然后,如果子查询的选择性很好,那么索引将有所帮助。选择性是行的百分比 select 与总行数进行比较。是50%,5%,0.5%吗?如果为5%或更低,则以下索引将有所帮助:

create index ix2_chat on chat (`to`, del_to_status, `from`, del_from_status);

请注意,列名不要使用保留字:我指的是from列。这只会让每个人的生活都很艰难。

5kgi1eie

5kgi1eie2#

我假设chat.id已被索引。如果没有,当然应该添加索引。
如果是索引的,mysql在子选择方面通常非常慢。
您可以做的一件事是将子选择转换为临时表并与之联接。
它看起来像

CREATE TEMPORARY TABLE IF NOT EXISTS max_chat_ids
                ( INDEX(id) ) 
                ENGINE=MEMORY
                AS ( 'SELECT MAX(id) as id FROM chat
  WHERE (`to` = 1 and `del_to_status` = '0') or (`from` = 1 and `del_from_status` = '0')
  GROUP BY CASE WHEN 1 = `to` THEN `from` ELSE `to` END' );

然后,只需连接temp表:

SELECT c.id, c.from, c.to, c.sent, c.message, c.recd FROM chat c 
join max_chat_ids d on c.id=d.id
ORDER BY c.id DESC
limit 60

临时表只在会话期间有效,因此如果在phpmyadmin中测试,请记住用“;”同时执行这两个查询在他们之间。
如果你尝试这个分享你的结果。

相关问题