Mysql 优化InnoDB表和有问题的查询

Mysql 优化InnoDB表和有问题的查询,mysql,clustered-index,Mysql,Clustered Index,我有一个更大的InnoDB表,目前它包含约2000万行,每天插入约20000个新行。它们包含不同主题的消息 CREATE TABLE IF NOT EXISTS `Messages` ( `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `TopicID` bigint(20) unsigned NOT NULL, `DATESTAMP` int(11) DEFAULT NULL, `TIMESTAMP` int(10) unsi

我有一个更大的InnoDB表,目前它包含约2000万行,每天插入约20000个新行。它们包含不同主题的消息

CREATE TABLE IF NOT EXISTS `Messages` (
  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `TopicID` bigint(20) unsigned NOT NULL,
  `DATESTAMP` int(11) DEFAULT NULL,
  `TIMESTAMP` int(10) unsigned NOT NULL,
  `Message` mediumtext NOT NULL,
  `Checksum` varchar(50) DEFAULT NULL,
  `Nickname` varchar(80) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `TopicID` (`TopicID`,`Checksum`),
  KEY `DATESTAMP` (`DATESTAMP`),
  KEY `Nickname` (`Nickname`),
  KEY `TIMESTAMP` (`TIMESTAMP`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=25195126 ;
注意:Cheksum存储一个MD5校验和,防止相同的消息在相同的主题中插入两次。(昵称+时间戳+主题ID+最后20个字符的消息)

我正在建设的网站有一个新闻提要,用户可以在其中选择查看来自不同论坛的不同昵称的最新消息。查询如下:

SELECT
Messages.ID AS MessageID,
Messages.Message,
Messages.TIMESTAMP,
Messages.Nickname,
Topics.ID AS TopicID,
Topics.Title AS TopicTitle,
Forums.Title AS ForumTitle

FROM Messages   

JOIN FollowedNicknames ON FollowedNicknames.UserID = 'MYUSERID'
JOIN Forums ON Forums.ID = FollowedNicknames.ForumID
JOIN Subforums ON Subforums.ForumID = Forums.ID
JOIN Topics ON Topics.SubforumID = Subforums.ID

WHERE 

Messages.Nickname = FollowedNicknames.Nickname AND 
Messages.TopicID = Topics.ID AND Messages.DATESTAMP = '2013619'
ORDER BY Messages.TIMESTAMP DESC
时间戳包含一个unix时间戳,DATESTAMP只是从unix时间戳生成的一个日期,以便通过“=”运算符更快地访问,而不是使用unix时间戳进行范围扫描

问题是,此查询需要大约13秒(或更长)的无缓冲时间。这对于预期用途来说当然是不可接受的。加上邮戳似乎加快了速度,但没有多大效果

在这一点上,我真的不知道我该怎么做。我已经读过关于复合主键的内容,但我仍然不确定它们是否有任何用处,以及在这种特殊情况下如何正确地实现一个复合主键

我知道使用bigint可能有点过火,但它们会影响那么多吗

说明:

+----+-------------+-----------------------+--------+---------------------------------------+------------+---------+-----------------------------------------------+------+----------------------------------------------+
| id | select_type | table                 | type   | possible_keys                         | key        | key_len | ref                                           | rows | Extra                                        |
+----+-------------+-----------------------+--------+---------------------------------------+------------+---------+-----------------------------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | FollowedNicknames     | ALL    | UserID,ForumID,Nickname               | NULL       | NULL    | NULL                                          |    8 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | Forums                | eq_ref | PRIMARY                               | PRIMARY    | 8       | database.FollowedNicknames.ForumiID           |    1 | NULL                                         |
|  1 | SIMPLE      | Messages              | ref    | TopicID,DATETIME,Nickname             | Nickname   | 242     | database.FollowedNicknames.Nickname           |   15 | Using where                                  |
|  1 | SIMPLE      | Topics                | eq_ref | PRIMARY,SubforumID                    | PRIMARY    | 8       | database.Messages.TopicID                     |    1 | NULL                                         |
|  1 | SIMPLE      | Subforums             | eq_ref | PRIMARY,ForumID                       | PRIMARY    | 8       | database.Topics.SubforumID                    |    1 | Using where                                  |
+----+-------------+-----------------------+--------+---------------------------------------+------------+---------+-----------------------------------------------+------+----------------------------------------------+

您不应该在
VARCHAR
列(
昵称
)上加入
;您应该使用用户ID连接这些表。这无疑会减慢查询速度,可能是最大的问题。如果您显式地编写所有的
JOIN
s,而不是在
WHERE
子句的末尾这样写,也会更容易理解:

SELECT
    Messages.ID AS MessageID,
    Messages.Message,
    Messages.TIMESTAMP,
    Messages.Nickname,
    Topics.ID AS TopicID,
    Topics.Title AS TopicTitle,
    Forums.Title AS ForumTitle
FROM Messages   
    JOIN FollowedNicknames ON Messages.Nickname = FollowedNicknames.Nickname
        AND FollowedNicknames.UserID = 'MYUSERID'
    JOIN Forums ON Forums.ID = FollowedNicknames.ForumID
    JOIN Subforums ON Subforums.ForumID = Forums.ID
    JOIN Topics ON Messages.TopicID = Topics.ID
        AND Topics.SubforumID = Subforums.ID
WHERE Messages.DATESTAMP = '2013619'
ORDER BY Messages.TIMESTAMP DESC

我不使用
INT
作为
DATESTAMP
列的数据类型,而是使用
DATE
Checksum
列可能应该使用
latin1\u general\u ci
作为排序规则。只要ID列的值小于2000000,我就使用
INT
,因为
INT UNSIGNED
可以存储大约4000000000的值。InnoDB受主键的影响比MyISAM大得多,它可能会产生明显的不同。

解释什么
有什么建议?添加了解释输出。感谢您的回复。但是,我不能使用userID加入,因为消息来自未注册的用户,因此唯一明智的方法是通过VARCHAR昵称列加入它们。