2011-07-13 60 views
0

我有两个表,名为login_log,记录了每个登录到网站的电子邮件的时间戳。另一个表称为admin并包含管理权限。两者都将电子邮件作为唯一标识符。Mysql查询优化,使用连接删除'NOT IN(SELECT CLAUSE)'

我想获得过去90天内未登录的所有电子邮件的列表。问题在于login_log表只记录每个使用时间戳记登录的电子邮件,它不会将最近的日志存储在用户登录的时间列表中。因此,我可以轻松地获取要保留的用户列表并使用我不想保留的'NOT'关键字。但它使用'NOT IN'语法非常慢。因此,下面的语句有一个子查询,它抓取了我想保留的最近90天内的所有电子邮件,外部抓取了我不想要的所有电子邮件。

SELECT distinct a.email FROM admin a WHERE a.email NOT IN (
    SELECT distinct a.email FROM admin a 
    INNER JOIN login_log ll ON a.email = ll.email AND 
    (ll.timestamp > UNIX_TIMESTAMP() - 7776000) /* 90 days in seconds */ 
); 

所以我的问题是什么将是一个很好的方法改变成一个JOIN或其他优化查询?

+0

是a.email索引列?有什么能阻止你简单地在某处添加last_login表? – lunixbochs

+0

'管理员'表可以包含具有相同电子邮件地址的多行吗? (我注意到你在上面使用了DISTINCT)。 – Femi

+0

@Femi是的,它可能会。有多个站点使用相同的表(使用字段merchant_id来区分),login_log表不是特定于站点的,但仍会有重复的电子邮件,因为每个登录都被记录下来。 – Aglystas

回答

1

这将返回所有的电子邮件,而不登录在过去90天内:

select distinct a.email, last_login 
from admin a 
inner join (
    select email, max(timestamp) as last_login 
    from login_log 
    group by email 
    ) ll 
on a.email = ll.email 
where last_login < unix_timestamp() - 7776000 

上login_log.email的指数将加速这一过程。

编辑:

这可能会更快:

select distinct a.email 
from admin a 
left outer join (
    select email 
    from login_log 
    where timestamp >= unix_timestamp() - 7776000 
    ) ll 
on a.email = ll.email 
where ll.timestamp is null 
+0

添加了另一个查询 –

1

尝试使用具有:

SELECT distinct a.email FROM admin a 
LEFT JOIN 
    (SELECT distinct a.email FROM admin a 
    INNER JOIN login_log ll ON a.email = ll.email 
     AND (ll.timestamp > UNIX_TIMESTAMP() - 7776000) 
    ) as tmp ON tmp.email = admin.email 
HAVING tmp.email IS NULL; 

虽然这仍然有一个子选择,它只能计算一次,而不是在管理每一次记录。它应该显着提高性能。

+0

这是一个很好的解决方案,但我不断收到语法错误,指出未知列。 – Aglystas