0

私は、現時点で約 2000 万行を含む大きな InnoDB テーブルを持っており、毎日 ~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 は、同じトピックに同じメッセージが 2 回挿入されるのを防ぐ 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

TIMESTAMP には UNIX タイムスタンプが含まれており、DATESTAMP は単に UNIX タイムスタンプから生成された日付であり、UNIX タイムスタンプを使用した範囲スキャンの代わりに「=」演算子を介してより高速にアクセスできます。

問題は、このクエリがバッファなしで約 13 秒 (またはそれ以上) かかることです。もちろん、意図した使用法では受け入れられません。DATESTAMP を追加すると速度が向上するように見えましたが、それほどではありませんでした。

この時点で、私は何をすべきか本当にわかりません。複合主キーについて読んだことがありますが、それらが有効かどうか、この特定のケースで正しく実装する方法はまだわかりません。

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                                  |
+----+-------------+-----------------------+--------+---------------------------------------+------------+---------+-----------------------------------------------+------+----------------------------------------------+
4

1 に答える 1

0

列 ( )JOINを ing するべきではありません。これらのテーブルを結合するには、ユーザー ID を使用する必要があります。これは間違いなくクエリの速度を低下させており、おそらく最大の問題です。次のように、句の最後ではなく、すべての s を明示的に記述した場合も、従うのが簡単になります。VARCHARNicknameJOINWHERE

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のデータ型の代わりに、. 列はおそらく照合として使用する必要があります。おおよそ 4,000,000,000 までの値を格納できるため、値が 2,000,000,000 未満である限り、ID 列に使用します。InnoDB は、MyISAM よりもはるかに主キーの影響を受け、顕著な違いを生む可能性があります。DATESTAMPDATEChecksumlatin1_general_ciINTINT UNSIGNED

于 2013-06-19T15:38:20.927 に答える