Показать последнее значение для каждого пользователя в SQL (быстро) - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь выяснить, было ли последнее действие для пользователя за последние 24 часа и не выполнено (это программное обеспечение, позволяющее узнать, какие люди все еще находятся в здании в случае чрезвычайной ситуации). В таблице около 2 миллионов строк, у нас около 3000 пользователей.

Единственное решение, которое я нашел, было ниже, оно работает, но проблема в том, что это занимает 15 секунд ...

SELECT TIME, firstname, lastname, dept
FROM DAY
WHERE event_point_id IN (20, 22, 24, 26, 28, 30)
  AND id IN (SELECT MAX(id)
             FROM DAY
             GROUP BY pin)
GROUP BY pin
ORDER BY TIME ASC

ДЕНЬ - вид со следующими деталями

SELECT id, pin, event_point_id, time, firstname, lastname, dept
FROM acc_monitor_log
WHERE (((TO_DAYS(NOW()) - TO_DAYS(time)) < 1) AND (pin <> '--'))

Какие могут быть варианты, чтобы ускорить это?

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

Если я правильно понимаю, ваше представление DAY уже фильтрует записи за последние 24 часа, и вам нужно получить только самую последнюю строку для каждого пользователя из этого представления.

Если это правильно, что-то простое, подобное этому, должно сработать, и, по моему мнению, должно быть быстрее, чем IN.

SELECT MAX(TIME), pin, firstname, lastname, dept
FROM DAY
WHERE event_point_id IN (20, 22, 24, 26, 28, 30)
GROUP BY pin, firstname, lastname, dept
ORDER BY TIME ASC
0 голосов
/ 06 сентября 2018

Во-первых, я бы использовал коррелированный подзапрос и избавился бы от GROUP BY:

SELECT d.TIME, d.firstname, d.lastname, d.dept
FROM DAY d
WHERE d.event_point_id IN (20, 22, 24, 26, 28, 30) AND
      d.id = (SELECT MAX(d2.id)
              FROM Day d2
              WHERE d2.pin = d.pin
             )
ORDER BY TIME ASC;

Затем убедитесь, что у вас есть индексы для базовой таблицы acc_monitor_log(pin, id) и acc_monitor_log(event_point_id, pin, id).

0 голосов
/ 06 сентября 2018

Первое предложение для сокращения предложения IN с использованием внутреннего соединения

SELECT TIME,firstname,lastname,dept
  FROM DAY
  INNER JOIN (
    SELECT pin, MAX(id) max_id 
    FROM DAY
    GROUP BY pin)
  ) T on t.max_id = DAY.id and t.pin = day.pin
  WHERE event_point_id IN (20,22,24,26,28,30)
  ORDER BY TIME ASC

или

SELECT TIME,firstname,lastname,dept
  FROM DAY
  INNER JOIN (
    SELECT pin, MAX(id) max_id 
    FROM DAY
    GROUP BY pin)
  ) T on t.max_id = DAY.id and t.pin = day.pin
  INNER JOIN (
    select 20 as my_point from dual
    union 
    select 22 from dual
     union 
    select 24 from dual       
    union 
    select 26 from dual
    union 
    select 28 from dual  
    union 
    select 30 from dual      
  ) t2  on t2.my_point  = DAY.event_point
  ORDER BY TIME ASC

и убедитесь, что у вас есть правильный индекс .. для столбца (pin, id), а также вы можете попробовать добавить правильную таблицу со значением 20 .... 30 с индексом вместо предложения IN или подзапроса и использовать соединение для этот стол

...