EXISTS

はっ、たまにはちゃんと仕事もしてるところを書いておかないと、延々神戸くん妄想してるだけだと思われてしまう!
というわけで仕事の話です。
今、MS-Accessでデータ書いたり読んだりするシステムをメンテしたりもしてるのですが、そのプログラムの接続先のデータベースが、SQLServermdbファイルの両方ありうる(エンドユーザによって違う)ので、SQLServerまたはAccessmdbファイルの両方に同じSQL文で問合せをしないとならなくて、中々難儀なのです。
こないだあったのは、EXISTSを使うとmdbファイルでの実行速度が死ぬほど遅い、という現象でした。
こんな感じです。
親テーブル:tableA(主キー:ID)
子テーブル:tableB(主キー:ID、XCode
以下の2つの条件のいずれかに該当するIDの件数を取得したい。
1. 子テーブルに、XCode=10のデータがある。
2. 子テーブルに、XCode=21のデータとXCode=22のデータが両方ある。

普通に


SELECT COUNT(*) FROM tableA
WHERE
(
EXISTS(
SELECT * FROM tableB
WHERE
tableB.XCode = 10
AND tableB.ID = tableA.ID
)
) OR (
EXISTS(
SELECT * FROM tableB
WHERE
tableB.XCode = 21
AND tableB.ID = tableA.ID
)
AND EXISTS(
SELECT * FROM tableB
WHERE
tableB.XCode = 22
AND tableB.ID = tableA.ID
)
)
てな感じで行けると思ったんですよ。そして実際ちゃんと件数取ってこられてたんですよ。
でもmdbファイルだと、件数増えると死ぬほど遅くなることが判明。親テーブルの件数が5000件超えたときなんて1時間ぐらいかかってましたよ。
ちょっとこれでは辛いので、作戦を変更。

SELECT COUNT(*)
FROM
(((
tableA AS a
LEFT JOIN (
SELECT * FROM tableB
WHERE
tableB.XCode = 10
) AS b10
ON a.ID = b10.ID
) LEFT JOIN (
SELECT * FROM tableB
WHERE
tableB.XCode = 21
) AS b21
ON a.ID = b21.ID
) LEFT JOIN (
SELECT * FROM tableB
WHERE
tableB.XCode = 22
) AS b22
ON a.ID = b22.ID
)
WHERE
(b10.ID IS NOT NULL)
OR (
b21.ID IS NOT NULL
AND b22.ID IS NOT NULL
)
ださいんだけどmdbファイルではこっちのが全然速いので仕方ないのです。
というわけで、状況によってアプローチは色々変えないとならないことがあるので、やっぱ色んな方法を知らないとですね、てのが今日の教訓。
全部が全部、スマートな環境で実行できるとは限らないのが実情です。しょんぼり。