Оптимизация запросов GROUP BY - PullRequest
6 голосов
/ 20 мая 2011

База данных MySQL с движком MyISAM.

Определение таблицы:

CREATE TABLE IF NOT EXISTS  matches  (
   id  int(11) NOT NULL AUTO_INCREMENT,
   game  int(11) NOT NULL,
   user  int(11) NOT NULL,
   opponent  int(11) NOT NULL,
   tournament  int(11) NOT NULL,
   score  int(11) NOT NULL,
   finish  tinyint(4) NOT NULL,
  PRIMARY KEY ( id ),
  KEY  game  ( game ),
  KEY  user  ( user ),
  KEY  i_gfu ( game , finish , user )
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3149047 ;

Я установил индекс на (game, finish, user), но для этого GROUP BY запроса по-прежнему требуется 0,4 - 0,6 секунды для выполнения:

SELECT user AS player
     , COUNT( id ) AS times
FROM matches
WHERE finish = 1
  AND game = 19
GROUP BY user
ORDER BY times DESC

Выход EXPLAIN:

| id | select_type | table   | type | possible_keys | key   | key_len | 
|  1 |  SIMPLE     | matches |  ref | game,i_gfu    | i_gfu |    5    | 

|  ref        |   rows |   Extra                                      |
| const,const | 155855 | Using where; Using temporary; Using filesort |

Есть ли способ сделать это быстрее? Таблица содержит около 800 тыс. Записей.


РЕДАКТИРОВАТЬ: я изменил COUNT(id) на COUNT(*), и время сократилось до 0,08 - 0,12 секунды. Я думаю, что пытался сделать это до создания индекса и забыл изменить его после.

В выводе объяснения Использование индекса объясняет ускорение:

|   rows |   Extra                                                   |
| 168029 | Using where; Using index; Using temporary; Using filesort |

(Дополнительный вопрос: это нормальное падение в 5 раз?)

Насчитывается около 2000 пользователей, поэтому окончательная сортировка, даже если она использует сортировку файлов, не снижает производительность. Я пытался без ORDER BY, и это все еще занимает почти то же время.

Ответы [ 6 ]

7 голосов
/ 20 мая 2011

Избавьтесь от ключа «игра» - он избыточен с «i_gfu». Поскольку 'id' является уникальным count (id), просто возвращает количество строк в каждой группе, поэтому вы можете избавиться от этого и заменить его на count (*). Попробуйте так и вставьте вывод EXPLAIN:

SELECT user AS player, COUNT(*) AS times
FROM matches
WHERE finish = 1
AND game = 19
GROUP BY user
ORDER BY times DESC
2 голосов
/ 20 мая 2011

Эх, круто. Попробуйте изменить порядок своего индекса: сначала поместите столбец user (так что индекс должен быть (user, finish, game)), поскольку это увеличивает вероятность того, что GROUP BY сможет использовать индекс. Однако, как правило, GROUP BY может использовать индексы только в том случае, если вы ограничиваете агрегатные функции, используемые MIN и MAX (см. http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html и http://dev.mysql.com/doc/refman/5.5/en/loose-index-scan.html).. Ваш заказ на самом деле тоже не помогает.

1 голос
/ 01 августа 2011

Одним из недостатков этого запроса является то, что вы упорядочиваете по совокупности. Это означает, что вы не можете возвращать строки, пока не будет создан полный набор результатов; индекс не может существовать (для mysql myisam, во всяком случае), чтобы это исправить.

Вы можете довольно легко денормализовать ваши данные, чтобы преодолеть это; Например, вы можете добавить триггер вставки / обновления, чтобы привязать значение счетчика в сводной таблице к индексу, чтобы вы могли сразу же начать возвращать строки.

1 голос
/ 20 мая 2011

Как уже отмечали другие, вы, возможно, достигли предела вашей способности настроить сам запрос.Далее вы должны увидеть, как настроены переменные max_heap_table_size и tmp_table_size на вашем сервере.По умолчанию установлено значение 16 МБ, что может быть слишком мало для вашей таблицы.

1 голос
/ 20 мая 2011

Я полагаю, что большая часть времени уходит на извлечение и, что более важно, сортировку (дважды, включая пропущенную при чтении индекса) 150 тыс. Строк из 800 тыс.Я сомневаюсь, что вы можете оптимизировать это намного больше, чем это уже есть.

1 голос
/ 20 мая 2011

EXPLAIN проверяет, что индекс (game, finish, user) использовался в запросе. Это кажется лучшим показателем для меня. Может ли это быть аппаратная проблема? Какая у вас система оперативной памяти и процессора?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...