2013-05-24 2 views
0

У меня есть 2 таблицы: 1) пользователь, в котором хранятся учетные данные пользователей. Он содержит более 1000 записей пользователей.SQL-запрос для выбора из двух довольно больших таблиц

ID | ИМЯ | ПАРОЛЬ | USERTYPEID

2) user_logs, в которых фиксируются данные для входа. Его довольно большой, то есть более 100000 записей.

ID | ИМЯ | DATEOFLOGIN | USERID | LOGINTYPE

Я должен найти пользователей, которые не имеют доступа к системе между двумя заданными датами и их последней зарегистрированной датой.

SELECT MAX(userlogs.dateoflogin) AS lastlogindate, 
     u1.id AS Id, 
     u1.name AS Name 
FROM USER u1 
LEFT OUTER JOIN user_logs userlogs ON u1.id = userlogs.userid 
WHERE u1.id NOT IN 
    (SELECT userid 
    FROM user_logs userlogs2 
    WHERE userlogs2.logtype='Login' 
     AND userlogs2.dateoflogin BETWEEN '2013-05-10' AND '2013-05-20' 
     AND userlogs2.userid IS NOT NULL) 
GROUP BY u1.id; 

Если в таблицах хранятся меньшие записи, тогда это работает хорошо. Но в живой системе, где таблица пользователя имеет более 1000 записей, а таблица user_logs содержит более 100000 записей, запрос занял очень много времени, и я не знаю, как это удалось или нет. :)

Как оптимизировать вышеуказанный запрос. Этот запрос также находит пользователя, который никогда не пытается войти в систему.

+0

У вас есть индекс в 'dateoflogin'? – Barmar

+0

да его проиндексирован на dateoflogin и userid – pinkb

ответ

0

Прежде всего, вам нужно изменить этот подзапрос, если вы хотите повысить производительность. Они удобны, но они имеют тенденцию значительно замедлять запрос.

Во-вторых, убедитесь, что у вас есть индексы во всех столбцах в предложении WHERE.

0

Это эквивалентно запросу, но LEFT JOIN с проверкой NULL часто бывает более эффективным, чем NOT IN.

SELECT MAX(userlogs.dateoflogin) as lastlogindate , u1.id as Id , u1.name as Name 
FROM user u1 
LEFT OUTER JOIN user_logs userlogs ON u1.id = userlogs.userid 
LEFT OUTER JOIN (SELECT distinct userid 
       FROM user_logs 
       WHERE logtype='Login' 
       AND dateoflogin BETWEEN '2013-05-10' AND '2013-05-20' 
       AND userid IS NOT null) userlogs2 ON u1.id = userlogs2.userid 
WHERE userlogs2.userid IS NULL 
GROUP BY u1.id 

Убедитесь, что индекс на dateoflogin так подзапрос будет хорошо.

Сравните выходные данные EXPLAIN с обоими запросами.

+0

Да, запрос выглядит отлично, но все же его длительное время занимает больше 10 минут и работает. Я еще не видел результата. Невозможно добиться того же результата с помощью JOIN без использования подзапроса. Имейте в виду, что user_logs содержит более 100000 записей, а также хранит записи выхода. – pinkb

+0

запрос, который вы предоставили, составил 1159477 мс (19 минут) для 1058920 пользователей и пользователей 29126. Это эффективно? или у нас есть другая возможность оптимизировать запрос. – pinkb

+0

Сколько времени занимает 'select count (*) из user_logs WHERE logtype = 'Login' AND dateoflogin BETWEEN '2013-05-10' AND '2013-05-20' И userid НЕ УДАЕТ? – Barmar

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