web-dev-qa-db-ja.com

非動的スカラーサブクエリは各行に対して評価されますか?

親クエリに依存しない(親テーブルを参照しない)スカラーサブクエリは、1回だけ評価されますか、それとも各行に対して評価されますか?

SELECT /* ... */
FROM
    t1
WHERE
    parent = (
        -- is this sq evaluated once?
        SELECT
            t2.id
        FROM t2
        WHERE t2.id = 10
    )

またはCTEを使用する

WITH parent_id AS (
    SELECT
        t2.id
    FROM t2
    WHERE t2.id = 10
)
SELECT /* ... */
WHERE
    parent = (
        SELECT p.id FROM parent_id p -- is this sq evaluated once?
    )

サブクエリ/ CTEが各行に対して評価されるという答えの場合、各行でCTEを結合すると、パフォーマンスが向上しますか?

WITH parent_id AS (
    SELECT
        t2.id
    FROM t2
    WHERE t2.id = 10
)
SELECT /* ... */
FROM
    t1, parent_id
WHERE
    parent = parent_id.id

また、EXPLAIN ANALYZEから式が何回評価されたかを把握する方法はありますか?

注:例は任意であり、実際のシナリオを反映していないため、サブクエリを実行して既知のid10)を見つけることは意味がないという事実を無視してください。

2
dwelle

一度評価されます。

EXPLAIN ANALYZEは、次のような行を表示します。

...
InitPlan 1 (returns $0)
    ->  Index Scan using t2_pkey on t2 (cost=0.29..5.31 rows=1 width=4) (actual time=0.024..0.025 rows=1 loops=1)
          Index Cond: (id = 10)
...

loops=1は、サブプランが一度だけ評価されたことを示します。 マニュアル:

一部のクエリプランでは、サブプランノードが複数回実行される可能性があります。たとえば、内側のインデックススキャンは、上記のネストされたループプランの外側の行ごとに1回実行されます。このような場合、loops値はノードの実行の総数を報告します[...]

次のようなcorrelatedサブクエリを使用します。

SELECT *, (SELECT id FROM t2 WHERE id = t1.parent_id) AS t2_id
FROM   t1;

(またはもっと便利なもの)loops=n、ここでnは行数t1です。

4