2013-06-19 5 views
0

У меня есть таблица Biggish InnoDB, которая в данный момент содержит около 20 миллионов строк с ~ 20000 новыми строками, вставленными каждый день. Они содержат сообщения для разных тем.Оптимизация таблицы InnoDB и проблемный запрос

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, которая предотвращает одновременное включение одинаковых сообщений в те же темы. (прозвище + отметка времени + тема + последние 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 секунд (или более) без буферизации. Это, конечно, неприемлемо для намеренного использования. Добавление DATESTAMP, казалось, ускорило ситуацию, но не сильно.

На данный момент я не знаю, что мне делать. Я читал о составных первичных ключах, но я по-прежнему не уверен, что они будут делать что-то хорошее и как правильно реализовать его в этом конкретном случае.

Я знаю, что использование BIGINT может немного переборщить, но они сильно влияют на это?

EXPLAIN:

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

Что предлагает 'EXPLAIN'? http://dev.mysql.com/doc/refman/5.0/en/explain.html – dash

+0

Добавлен вывод EXPLAIN. –

ответ

0

Вы не должны быть JOIN ИНГ на VARCHAR колонке (Nickname); вы должны использовать идентификатор пользователя, чтобы присоединиться к этим таблицам. Это определенно замедляет запрос и, вероятно, является самой большой проблемой. Было бы легче следовать, если вы написали все JOIN с явно, а не в конце в пункте 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_general_ci в качестве сортировки. Я бы использовал INT для столбцов ID, если их значения меньше 2 000 000 000, поскольку INT UNSIGNED может хранить значения до примерно 4 000 000 000. На InnoDB влияет первичный ключ намного больше, чем MyISAM, и это может иметь заметную разницу.

+0

Спасибо за ваш ответ. Тем не менее, я не могу присоединиться к userID, потому что сообщения от незарегистрированных пользователей, и поэтому единственным разумным способом является объединение их с помощью столбца псевдонима VARCHAR. –

 Смежные вопросы

  • Нет связанных вопросов^_^