QA@IT
«回答へ戻る

回答を投稿

Aテーブルのレコード数が不明ですが、Bテーブルより格段に少ないんですよね?
existsは該当レコードが見つかった時点でスキャンを打ち切るのでcountより高速ですが、not existsは無いことを確かめるために全スキャンするはずなので、あまり速くありません。
なので、スキャン対象をAテーブルにすると多少マシになりはしないでしょうか。

あんまり変わらない気もしますが、CTE使うと結果セットを一時保持してくれるので、Bテーブルの全インデックススキャンより速くなるかも。。
jijiさんのselect文をお借りするとこんな感じになるのかな。
シンプルじゃなくなってますが。

WITH cte (id)
AS
(
  SELECT A.id
  FROM A
  WHERE
  EXISTS (
    SELECT 1
    FROM B
    WHERE B.a_id = A.id
  )
)
SELECT
A.id,
CASE WHEN EXISTS(SELECT 1 FROM cte WHERE cte.id = A.id) THEN 1 ELSE 0
END AS B_exists
FROM A

あと気を付ける点としては、Bテーブルのa_id列にインデックスが欲しいことと、EXISTS内の相関サブクエリのSELECTは定数にした方が良いくらいでしょうか。
後者はオプティマイザがいいように解釈してくれそうな気もしますけれど。

Aテーブルのレコード数が不明ですが、Bテーブルより格段に少ないんですよね?
existsは該当レコードが見つかった時点でスキャンを打ち切るのでcountより高速ですが、not existsは無いことを確かめるために全スキャンするはずなので、あまり速くありません。
なので、スキャン対象をAテーブルにすると多少マシになりはしないでしょうか。

あんまり変わらない気もしますが、CTE使うと結果セットを一時保持してくれるので、Bテーブルの全インデックススキャンより速くなるかも。。
jijiさんのselect文をお借りするとこんな感じになるのかな。
シンプルじゃなくなってますが。

```sql
WITH cte (id)
AS
(
  SELECT A.id
  FROM A
  WHERE
  EXISTS (
    SELECT 1
    FROM B
    WHERE B.a_id = A.id
  )
)
SELECT
A.id,
CASE WHEN EXISTS(SELECT 1 FROM cte WHERE cte.id = A.id) THEN 1 ELSE 0
END AS B_exists
FROM A
```

あと気を付ける点としては、Bテーブルのa_id列にインデックスが欲しいことと、EXISTS内の相関サブクエリのSELECTは定数にした方が良いくらいでしょうか。
後者はオプティマイザがいいように解釈してくれそうな気もしますけれど。