MySQL никогда не завершает запрос подзапросом, но завершается, когда запросы выполняются отдельно

#mysql #sql

Вопрос:

Это запрос, который никогда не заканчивается:

 SELECT modelId, `timestamp` FROM thread_view WHERE id IN 
  (SELECT max(id) FROM thread_view
   WHERE viewerId = 1 AND modelType = 'LEASE' AND modelId IN 
   (15,615,618,660) GROUP BY modelId);
 

Когда я запускаю только подзапрос, он завершается за 12 мс и возвращает два идентификатора. Когда я жестко кодирую эти 2 идентификатора вместо подзапроса, внешний запрос возвращает две строки и завершается за 0,3 мс.

Как вы можете видеть, обе части запроса выполняются невероятно быстро, и не похоже, что мы имеем дело с большим количеством данных. Когда я запускаю ОБЪЯСНЕНИЕ:

результаты ОБЪЯСНЕНИЯ

Объяснение не выявило у меня никаких проблем. Это просто ошибка с MySQL?

РЕДАКТИРОВАТЬ: mysql —версия дает: mysql версии 8.0.25 для macos11.3 на x86_64 (Доморощенный)

ПРАВКА №2: Как и было запрошено, вот инструкция create table:

 CREATE TABLE `thread_view` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `timestamp` bigint DEFAULT NULL,
  `viewerId` bigint DEFAULT NULL,
  `modelType` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `modelId` bigint DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `viewerId_modelType_modelId` (`viewerId`,`modelType`,`modelId`)
) ENGINE=InnoDB AUTO_INCREMENT=50582 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
 

Комментарии:

1. Не могли бы вы обновить вопрос текстом CREATE VIEW заявления и CREATE TABLE утверждениями (или другими), связанными с любыми базовыми объектами, к которым осуществляется доступ VIEW ?

2. Обратите dependent subquery внимание на план объяснения. Это часто является причиной проблем с производительностью. Это говорит о том, что либо ошибка, либо ваш SQL не является репрезентативным, либо у нас недостаточно подробностей в вопросе. Эти неквалифицированные ссылки на столбцы всегда должны разрешаться ближайшим объектом. В этом случае у вас есть один объект-представление. Таким образом, в SQL, который вы показали, действительно не должно быть никакого коррелированного / зависимого поведения. Может быть, в скрытом VIEW определении есть что-то, что вызывает это. Трудно сказать без этой детали.

3. извините, что это вводит в заблуждение, но thread_view на самом деле не является ПРЕДСТАВЛЕНИЕМ, это просто обычная таблица. Кроме того, это не «проблема с производительностью», запрос никогда не завершится, независимо от того, как долго он выполняется-и строк не так много.

4. ОК. Это прекрасно. Пожалуйста, покажите это определение (текст CREATE TABLE ). Я не вижу никаких причин для DEPENDENT такого поведения. Вы уверены, что это «точный» SQL?

5. @JonArmstrong Добавил!

Ответ №1:

Если цель действительно состоит в том, чтобы захватить наибольшую отметку времени для каждой модели (также отмечено @Shaharyar):

 SELECT modelId
     , MAX(`timestamp`)
  FROM thread_view
 WHERE modelId IN (15,615,618,660)
   AND viewerId = 1
   AND modelType = 'LEASE'
 GROUP BY modelId
;
 

Ответ №2:

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

Но если предположить, что id это уникально, то попробуйте:

 select t.*
from (select  t.*,
             row_number() over (partition by modelId order by id desc) as seqnum
      from thread_view t
      where viewerId = 1 and
            modelType = 'LEASE' and
            modelId in (15, 615, 618, 660)
     ) t
where seqnum = 1;
 

Комментарии:

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

2. @satnam если вы хотите получить last timestamp для каждой модели, почему бы не сделать max(timestamp) это ? Вместо того, чтобы выбирать id первое, а затем выбирать timestamp против этого id

3. @Shaharyar интересная мысль, но я не совсем уверен, как это будет выглядеть-у вас есть пример запроса?

4. SELECT modelId, MAX(`timestamp`) FROM thread_view WHERE modelId IN (15,615,618,660) AND viewerId = 1 AND modelType = 'LEASE' GROUP BY modelId;