Почему может тормозить простейший запрос?

MySQL 5.7
SELECT vk_user_id, COUNT(1) AS score FROM vk_scores WHERE page_id IN (SELECT page_id FROM blitz_tasks WHERE stage = 1533) GROUP BY vk_user_id

EXPLAIN:
1	SIMPLE	blitz_tasks	NULL	ref	page_id,stage,stage_index	stage_index	4	const	193	100.00	Using temporary; Using filesort	
1	SIMPLE	vk_scores	NULL	ref	vk_user_id_2,vk_user_id,page_id	page_id		4	blitz_tasks.page_id	179	100.00	NULL

Индексы есть на все подряд, собственно, EXPLAIN их показывает.
Внутренний подзапрос к blitz_tasks выпоняется за 8 миллисекунд, и там меньше 200 результатов.
В таблице vk_scores под миллион записей, но всего 4 поля, запрос выдает 600 результатов.
НАД ЧЕМ тут думать 4 секунды?
И какого "Using temporary; Using filesort" при выборке по индексу?
EXPLAIN самого подзапроса, естественно, ничего такого не показывает.
Запросы с IN и JOIN тех же таблиц инвариантны, один и тот же план.

P.S. Проблема появилась с переездом на новый сервер, до того все было пучком, и на сервере разработки тот же запрос на тех же данных с тем же планом отрабатывает за 0,04 секунды.
P.P.S. Таблицы:
CREATE TABLE `blitz_tasks` (
  `page_id` int NOT NULL,
  `stage` int NOT NULL,
  `start` datetime NOT NULL,
  `end` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3;

ALTER TABLE `blitz_tasks`
  ADD UNIQUE KEY `page_id` (`page_id`),
  ADD KEY `stage` (`stage`,`start`),
  ADD KEY `stage_index` (`stage`);

CREATE TABLE `vk_scores` (
  `id` int NOT NULL,
  `vk_user_id` decimal(15,0) NOT NULL,
  `page_id` int NOT NULL,
  `kk_user_id` int NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3;

ALTER TABLE `vk_scores`
  ADD PRIMARY KEY (`id`),
  ADD KEY `vk_user_id` (`vk_user_id`),
  ADD KEY `page_id` (`page_id`);
ALTER TABLE `vk_scores`
  MODIFY `id` int NOT NULL AUTO_INCREMENT;
  • Вопрос задан
  • 284 просмотра
Решения вопроса 1
Adamos
@Adamos Автор вопроса
Уличная магия с полным ее... в общем, полным.
У ТП хостера наконец дошли руки до моего тикета... и вдруг все заработало.
Тот же самый запрос выполняется, как положено, за миллисекунды.
В тех переменных, которые можно увидеть по SHOW VARIABLES, никаких изменений не произошло.
Единственная зацепка насчет причин - на старом сервере был MySQL 5.6, на новом - 5.7.
Впрочем, на сервере разработки у меня вообще MariaDB 8, и оно ему ни разу не мешало.

Спасибо за участие, джентльмены. Это было что-то выше нас ;)

P.S. График нагрузки у хостера через неделю. Явно видно, что конкретные запросы были ни при чем...
63d39bbfe5996082650837.png
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
@rPman
В чем отличия в серверах? количество оперативной памяти? мажорная версия mysql? настройки?
есть возможность сравнить конфигурации mysql прошлого сервера и нового с помощью SHOW VARIABLES и уже сравнив их на примере каких-нибудь буферов можно что то менять.

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

Вот посмотри тут как предлагают проверить, влезает ли индекс в память или нет (подправь там условие чтобы твои таблицы были а не все)
--------------------------------

Так же предлагаю провести эксперимент, замени SELECT page_id FROM blitz_tasks WHERE stage = 1533 на список значений в константах (1,2,3,4,...), и если это поможет (а должно так как запрос теперь лезет только в одну таблицу и не трогает другие индексы) то будешь дробить свои запросы, избавляясь от вложенностей и нескольких индексов в одном запросе
Ответ написан
BasiC2k
@BasiC2k
.NET developer (open to job offers)
Внутренний подзапрос к blitz_tasks у Вас выполняется для каждой строки.
Вам нужно использовать LEFT JOIN и правильно расставить индексы.
Ответ написан
@Akina
Сетевой и системный админ, SQL-программист.
Для начала отформатируем запрос - чтобы хоть что-то было видно.
SELECT vk_user_id, COUNT(1) AS score 
FROM vk_scores 
WHERE page_id IN (
    SELECT page_id 
    FROM blitz_tasks 
    WHERE stage = 1533
    ) 
GROUP BY vk_user_id

Учитываем, что blitz_tasks.page_id определён как NOT NULL UNIQUE (кстати, а почему не как PRIMARY KEY?), значит, запрос элементарно переписывается на INNER JOIN:
SELECT vk_scores.vk_user_id, COUNT(*) AS score 
FROM vk_scores 
JOIN blitz_tasks USING (page_id)
WHERE blitz_tasks.stage = 1533
GROUP BY vk_scores.vk_user_id
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы