2011-07-13 5 views
0

login_logという2つのテーブルがあり、Webサイトにログインする各メールのタイムスタンプを記録します。もう一方のテーブルは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

'admin'テーブルに同じ電子メールアドレスを持つ複数の行を含めることはできますか? (私は上記のDISTINCTを使用していることに気付きました)。 – Femi

+0

@Femiはい、それは可能性があります。同じテーブルを使用する複数のサイトがあります(区別するためにmerchant_idフィールドを使用しています).login_logテーブルはサイト固有ではありませんが、すべてのログインが記録されるため、メールは重複しています。 – Aglystas

答えて

1

これは過去90日間にログインせずにすべての電子メールを返します。login_log.email上

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 

インデックスは、それをスピードアップするでしょう。

EDIT:

これは速いかもしれない:

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

HAVING使用してみてください:

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; 

をこれでもサブ選択、それだけではなく、レコードごとに一度adminに、一度計算されていますが。パフォーマンスが大幅に向上するはずです。

+0

これはすばらしい解決策ですが、未知の列を示す構文エラーが続いています。 – Aglystas

関連する問題