2014-09-09 3 views
0

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

Первый стол GameHistory, в котором я храню записи для каждой законченной игры (у меня 15 игр в отдельной таблице). Поля: id, date_end, game_id, ..

Второй стол GameHistory Участники, в которых я храню записи для каждого игрока, участвовавшего в определенной игре. Поля: player_id, history_id, is_winner

Запрос на получение лучших игроков сегодня очень медленный (20+ секунд). Запрос:

SELECT p.nickname, count(ghp.player_id) as num_games_today 
FROM `GameHistory` as gh 
INNER JOIN GameHistoryParticipants as ghp ON gh.id=ghp.history_id  

INNER JOIN Players as p ON p.id=ghp.player_id  

WHERE TIMESTAMPDIFF(DAY, gh.date_end, NOW())=0 AND gh.game_id='scrabble' 

GROUP BY ghp.player_id ORDER BY count(ghp.player_id) DESC LIMIT 10 

Первая таблица имеет 1,5 миллиона записей, а второй 3,5 млн. Какие индексы я должен поставить? (Я пробовал некоторые, и все было медленно)

+0

* Очень медленно * - как медленно мы говорим? Как вы измеряете скорость? – jbutler483

+0

27 секунд. Я запускаю запрос в phpMyAdmin, и он сообщает мне, что –

+0

имеет: http: //bytes.com/topic/sql-server/answers/142644-create-index-large-table – jbutler483

ответ

0

добавить команду «EXPLAIN» в начале вашего запроса, затем запустить ее в средстве просмотра базы данных (например: sqlyog), и вы увидите подробности о запросе, найдите столбец «rows», и вы увидите разные целочисленные значения. Теперь проиндексируйте столбцы таблицы, указанные в результате команды команды EXPLAIN, которые содержат большие строки.

-Думает мое объяснение своего рода грязное, вы можете попросить разъяснения

1

Вы заинтересованы только в современных записях. Тем не менее, вы просматриваете всю таблицу GameHistory с помощью TIMESTAMPDIFF для обнаружения этих записей. Даже если у вас есть индекс в этом столбце, его нельзя использовать из-за того, что вы используете функцию в поле.

У вас должен быть указатель на оба поля game_id и date_end. Затем запрашиваете значение date_end непосредственно:

WHERE gh.date_end >= DATE(NOW()) 
AND gh.date_end < DATE_ADD(DATE(NOW()), INTERVAL 1 DAY) 
AND gh.game_id = 'scrabble' 

Было бы даже лучше иметь индекс части даты date_end в, а затем на все время проведения date_end. Однако это невозможно в MySQL. Поэтому рассмотрите возможность добавления другого столбца trunc_date_end только для части даты, которую вы заполняете триггером перед вставкой. Тогда у вас будет указатель на trunc_date_end и game_id, который поможет вам быстро найти нужные записи.

WHERE gh.trunc_date_end = DATE(NOW()) 
AND gh.game_id = 'scrabble' 
+0

Очень полезно - спасибо, я попробую, но у меня есть похожие запросы, чтобы получить не только сегодняшних лучших игроков, но еженедельно сверху и ежемесячно. Странно то, что после добавления индексов game_id и date_end это не получилось намного быстрее, но когда я удалил соединение в таблицу Players - он стал быстрым (1сек) –

+0

Это, безусловно, странно, потому что на игроках должен быть внешний ключ в ghp стол, правда? Поэтому получение записей Player должно быть очень быстрым. (BTW: Если в таблице есть много столбцов, вы всегда можете использовать трюк для создания индекса на id + nickname, поэтому достаточно прочитать индекс самостоятельно, не имея доступа к таблице.) –

+0

Что касается еженедельного и ежемесячного верха: Это не имеет значения. Вас интересует только часть данных таблицы, поэтому можно использовать индекс с прямым доступом к столбцу ('gh.date_end> = ...', 'gh.date_end <= ...' или даже 'gh.trunc_date_end = ... ') должно ускорить процесс. –

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