2011-07-13 59 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