SQL-запрос для выбора всех строк с максимальным значением столбца - PullRequest
0 голосов
/ 31 октября 2018
CREATE TABLE `user_activity` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `type` enum('request','response') DEFAULT NULL,
  `data` longtext NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `source` varchar(255) DEFAULT NULL,
  `task_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

У меня есть эти данные: -

enter image description here

Теперь мне нужно выбрать все строки для user_id=527, где значение created_at является максимальным. Поэтому мне нужны последние 3 строки на этом изображении.

Я написал этот запрос: -

SELECT * 
FROM   user_activity 
WHERE  user_id = 527 
       AND source = 'E1' 
       AND task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' ) 
       AND created_at = (SELECT Max(created_at) 
                         FROM   user_activity 
                         WHERE  user_id = 527 
                                AND source = 'E1' 
                                AND task_name IN ( 'GetReportTask', 
                                                   'StopMonitoringUserTask' ));

Это очень неэффективно, потому что я снова выполняю тот же запрос, что и внутренний, за исключением того, что он игнорирует created_at. Какой правильный способ сделать это?

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

Я бы использовал коррелированный подзапрос:

SELECT ua.* 
FROM user_activity ua
WHERE ua.user_id = 527 AND source = 'E1' AND
      ua.task_name IN ('GetReportTask', 'StopMonitoringUserTask' ) AND
      ua.created_at = (SELECT MAX(ua2.created_at) 
                       FROM user_activity ua2
                       WHERE ua2.user_id = ua.user_id AND 
                             ua2.source = ua.source AND
                             ua2.task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' )
                      );

Хотя это может показаться неэффективным, вы можете создать индекс для user_activity(user_id, source, task_name, created_at). С этим индексом запрос должен иметь приличную производительность.

0 голосов
/ 31 октября 2018

Я использовал EverSQL и применил свои собственные изменения, чтобы создать запрос с одним выбором, использующий самосоединение: -

SELECT * 
FROM   user_activity AS ua1 
       LEFT JOIN user_activity AS ua2 
              ON ua2.user_id = ua1.user_id 
                 AND ua2.source = ua1.source 
                 AND ua2.task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' ) 
                 AND ua1.created_at < ua2.created_at 
WHERE  ua1.user_id = 527 
       AND ua1.source = 'E1' 
       AND ua1.task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' ) 
       AND ua2.created_at IS NULL;

Однако я заметил, что время ответа на оба запроса было одинаковым. Я пытался использовать Объяснить , чтобы определить любые различия в производительности; и из того, что я понял из его вывода, нет никаких заметных различий, потому что надлежащая индексация на месте. Так что для удобочитаемости и удобства обслуживания я просто буду использовать вложенный запрос.

0 голосов
/ 31 октября 2018

Упорядочить по create_at desc и ограничить ваш запрос до 1 строки.

SELECT * 
FROM   user_activity 
WHERE  user_id = 527 
   AND source = 'E1' 
   AND task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' ) 
ORDER BY created_at DESC
LIMIT 1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...