2016-12-31 3 views
0

У меня есть эта схема, которая сохраняет сообщения чата. В настоящее время у меня около 100 тыс. Строк, что составляет около 5,5 МБ данных. Размер индекса - 6,5 МБ. Когда размер данных составлял ~ 4 МБ, размер индекса составлял ~ 3 МБ, поэтому он растет экспоненциально?Оптимизируйте таблицу, чтобы уменьшить размер индекса

CREATE TABLE `messages` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `author` int(11) unsigned DEFAULT NULL, 
    `time` int(10) unsigned DEFAULT NULL, 
    `text` text, 
    `dest` int(11) unsigned DEFAULT NULL, 
    `type` tinyint(4) unsigned DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `history` (`author`,`dest`,`id`) USING BTREE, 
    KEY `messages_ibfk_1` (`dest`), 
    FULLTEXT KEY `msg` (`text`), 
    CONSTRAINT `au` FOREIGN KEY (`author`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 
    CONSTRAINT `messages_ibfk_1` FOREIGN KEY (`dest`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=105895 DEFAULT CHARSET=utf8; 

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

SELECT id, time, text, dest, type, author 
FROM `messages` 
WHERE (
    (author = ? AND dest = ?) OR (author = ? AND dest = ?) 
) AND id <= ? ORDER BY id DESC LIMIT ?, 25 

другие запросы для истории идентичны, за исключением того, что у них есть дополнительные фильтры для поискового запроса или диапазона дат.

Есть ли что-нибудь, что можно сделать для уменьшения размера индекса и поддержания оптимальной производительности?

+0

Почему, по вашему мнению, размер индекса имеет какое-либо отношение к производительности? Ваши запросы работают медленно? В конце концов, если у вас не было индексов, вы бы сэкономили много места, но ваши запросы были бы намного медленнее, поэтому, очевидно, что индекс является чем-то вроде компромиссов по пространству и с индексом вообще, вы мы выразили желание иметь производительность за счет пространства. –

+0

Ваш индекс может быть больше, чем сама таблица, если MySQL оставляет некоторое незаполненное пространство в btree в ожидании будущих вставок. –

+0

Кстати, вы можете уменьшить размер вашего индекса и повысить производительность запроса, сохранив «user1» и «user2» вместо «author» и «dest», упорядочив двух пользователей в алфавитном порядке и сделав «user1» первым пользователем и «user2» - второй. Поэтому, если вы хотите найти разговоры между Марком и Алисой, Алиса всегда будет «user1», а Mark всегда будет «user2». Затем вы можете добавить еще один столбец, чтобы указать, является ли «user1» автором или получателем. –

ответ

1

Не беспокойтесь о росте индексов. Вероятно, это случайность; конечно, не «экспоненциальный».

Предполагая, что главный вопрос является выполнением

SELECT id, time, text, dest, type, author 
FROM `messages` 
WHERE (
    (author = ? AND dest = ?) OR (author = ? AND dest = ?) 
) AND id <= ? ORDER BY id DESC LIMIT ?, 25 

Я вижу три метода, которые существенно помогут: Изменить OR в UNION, иметь дело с LIMIT в UNION, и не использовать OFFSET для пагинации.

 (SELECT id, time, text, dest, type, author 
      FROM `messages` 
      WHERE author = ? -- one author & dest 
       AND dest = ? 
       AND id < ? -- where you "left off" 
      ORDER BY id DESC 
      LIMIT 25 
     ) UNION ALL 
     (SELECT id, time, text, dest, type, author 
      FROM `messages` 
      WHERE author = ? -- the other author & dest 
       AND dest = ? 
       AND id < ?  -- same as above 
      ORDER BY id DESC 
      LIMIT 25 
     ) 
     ORDER BY id DESC 
     LIMIT 25;   -- get the desired 25 from the 50 above 

Pagination discussion объясняет, почему OFFSET должны быть удалены. В нем обсуждаются другие методы, в том числе использование 26 (во всех трех местах) вместо 25, чтобы вы знали, является ли это «последней» страницей.

На первой итерации AND id < ? можно оторвать. Или (проще), вы можете заменить очень большое число.

Ваш индекс (author, dest, id) является оптимальным для моей формы.

Эта сложная формулировка будет светиться, так как messages получает больше и/или страницы пользователя дальше по списку.

+0

Эта формулировка затрагивает не более 50 строк (плюс запись 50 в tmp и перечитывание 50), независимо от размера таблицы или номера страницы. Первоначальная формулировка всегда касалась большинства или всех строк. –

+0

Спасибо за этот ответ, это было очень полезно - особенно часть об избежании использования смещения для разбивки на страницы, я столкнулся с этой проблемой в прошлом. Однако вопрос был о том, является ли этот размер индекса приемлемым и как его уменьшить, потому что IMH (noob) O с индексом, большим, чем мои данные, кажется из-под контроля - вот почему я не буду отмечать ответ как принятый. –

+0

Также я подумал, что стоит указать - запустить исходный запрос из вопроса без смещения возвращается в 1 мс, но получая те же результаты с возвратом объединения в 50 мс. Я помню, что я тестировал это также, когда я разрабатывал таблицу, и это было так же тогда - 'OR' превосходит« UNION »много раз. –