选择花8秒。改善想法

时间:2018-06-11 14:47:58

标签: mysql sql

我有这个选择来聊天(比如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`)
)

enter image description here

任何关于索引或重写这个选择以获得更好速度的想法?

2 个答案:

答案 0 :(得分:1)

我假设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' );

然后,你需要加入临时表:

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中进行测试,请记住同时执行两个查询&#39 ;;'它们之间。

如果您尝试分享您的结果。

答案 1 :(得分:0)

我假设列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);

作为旁注,请不要在列名中使用保留字:我正在谈论来自列。它只会让每个人的生活变得困难。