2011年2月1日火曜日

MySQLでNOT INの代わりにNOT EXISTSを使うと速い

ちょっとした情報を取り出す時のクエリが30秒ほどかかったので、何とか改善できないものかと試行錯誤してみました。

2つのテーブルがあって、仮に

■顧客情報
t_client_info ( client_id, name, address)
■顧客履歴
t_client_history (id, client_id, visit_date)

とでもしましょう。

visit_dateはdate型ではなくてint型でYYYYMMDDの形式とします。
あとは見たまんまなのでテーブルの説明は省略ます。

2010年の元旦から1年以内に来店した顧客の住所と最終来店日を取得するというクエリです。
1年のうちに1回しか来なかった人は省くことにします。


SELECT i.client_id, name, address, MAX(visit_date) as vdate
FROM t_client_info AS i
LEFT JOIN t_client_history AS h
ON i.client_id = h.client_id
WHERE visit_date > 20100101
AND i.client_id NOT IN (
SELECT client_id
FROM t_client_history
WHERE visit_date > 20100101
GROUP BY client_id
HAVING COUNT(visit_date) = 1
)

GROUP BY i.client_id, name, address
ORDER BY vdate DESC


こんな感じでやってみると、30秒かかりました。
サブクエリ単体の実行速度はそんなに遅くなかったので、多分NOT INがダメなんだろうなと思って、NOT EXISTSを使ってみることに。


SELECT i.client_id, name, address, MAX(visit_date) as vdate
FROM t_client_info AS i
LEFT JOIN t_client_history AS h
ON i.client_id = h.client_id
WHERE visit_date > 20100101
AND NOT EXISTS (
SELECT client_id
FROM t_client_historr
WHERE visit_date > 20100101
AND i.client_id = client_id
GROUP BY client_id
HAVING COUNT(visit_date) = 1
)

GROUP BY i.client_id, name, address
ORDER BY vdate DESC


こんな感じになりました。
これで一瞬で表示されました。

NOT INの方が読みやすいんですけどね。
ここまで速度に差が出ると可読性なんてこだわってられません。

0 件のコメント:

コメントを投稿