Оптимизация индекса таблицы MySQL

Я работаю с приложением, которое имеет базу данных MySQL на Amazon RDS. Таблица вопросов задается так:

CREATE TABLE `log` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `timestamp` datetime NOT NULL,
  `username` varchar(45) NOT NULL,
  .. snip some varchar and int fields ..
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

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

SELECT COUNT(*) FROM log --> 16307224 (takes 105 seconds to complete)

Эта таблица в основном используется только для создания одного отчета по запросу, подобному этому

SELECT timestamp, username, [a few more] FROM log 
WHERE timestamp  BETWEEN '2012-03-30 08:00:00' AND '2012-03-30 16:00:00' 
AND username='XX' 

Что обычно дает от 1000 до 6000 строк, что занимает около 100-180 секунд, а это означает, что веб-приложение будет часто зависать и оставит пустой отчет (я также посмотрю на время ожидания, но этот вопрос относится к корню причина).

Я не очень хорошо разбираюсь в базах данных, но я думаю, что именно МЕЖДУ убивает меня здесь. Я думаю, что, возможно, мне следует каким-то образом использовать метку времени в качестве индекса. Временная метка с именем пользователя по-прежнему должна обеспечивать уникальность (я ни для чего не использую поле id).

Если есть кто-то там с предложениями по оптимизации, я весь слух.

ОБНОВИТЬ:

Таблица теперь изменена на следующую

CREATE TABLE `log` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `timestamp` datetime NOT NULL,
  `username` varchar(45) NOT NULL,
  .. snip ..
  `task_id` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_un_ts` (`timestamp`,`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

EXPLAIN из SELECT оператор возвращает следующее

id => 1
select_type => SIMPLE
table => log
type => range
possible_keys => index_un_ts
key => index_un_ts
key_len => 55
ref => 
rows => 52258
Extra => Using where; Using index

1 ответ

Решение

Ну, индекс в столбце timestamp и ID пользователя будет полезен. Вы должны быть в состоянии прочитать выходные данные оператора EXPLAIN.

Перейдите в MySQL и выполните следующее:

EXPLAIN SELECT timestamp, username, [a few more] FROM log 
WHERE timestamp  BETWEEN '2012-03-30 08:00:00' AND '2012-03-30 16:00:00' 
AND username='XX' 

Это покажет вам план, который MySQL использует для выполнения запроса. Там будет столбец с именем ключа. Это указывает, какой индекс MySQL использует в запросе. Я подозреваю, что вы увидите там ВСЕ, что означает, что MySQL сканирует таблицу сверху вниз, сопоставляя каждую строку с вашим предложением where. Теперь создайте индекс для столбцов timestamp и userid. Запустите оператор EXPLAIN еще раз. Вы должны увидеть индекс, который вы создали в ключевом столбце.

Если MySQL использует индекс, тогда ваш запрос должен быть значительно быстрее. Просто помните, чтобы не переоценить. Индексы делают вставки, обновления и удаления медленнее. Когда вы вставляете новую строку в таблицу и в таблице есть три индекса, новая строка должна записать 3 значения в три разных индекса. Так что это обоюдоострый меч.

Другие вопросы по тегам