私のフォローアップ Postgres 12の一部のクエリが11のクエリよりも遅いという質問 問題を絞り込むことができたと思います。関数値に基づいた1つの再帰CTEが問題のスポットのようです。
Postgres 12.1では約150ミリ秒、Postgres 11.6では約4ミリ秒のように、Postgres 12.1ではPostgres 11.6よりもかなり長く実行されるかなり小さめのSQLクエリを分離できました。この現象をさまざまなシステムで再現できました。VirtualBoxの複数のVMで。 2つの異なる物理マシン上のDockerを介して。 (Dockerコマンドについては付録を参照してください)。しかし、奇妙なことに、それを https://www.db-fiddle.com/ で再現することはできません(違いはありません。どちらも高速です)。
さて、クエリについて。まず、この単純な関数を作成します
CREATE OR REPLACE FUNCTION public.my_test_function()
RETURNS SETOF record
LANGUAGE sql
IMMUTABLE SECURITY DEFINER
AS $function$
SELECT
1::integer AS id,
'2019-11-20'::date AS "startDate",
'2020-01-01'::date AS "endDate"
$function$;
次に、実際のクエリ
WITH "somePeriods" AS (
SELECT * FROM my_test_function() AS
f(id integer, "startDate" date, "endDate" date)
),
"maxRecursiveEndDate" AS (
SELECT "startDate", "endDate", id,
(
WITH RECURSIVE prep("startDateParam", "endDateParam") AS (
SELECT "startDate","endDate" FROM "somePeriods" WHERE id = od.id
UNION
SELECT "startDate","endDate" FROM "somePeriods", prep
WHERE
"startDate" <= ("endDateParam" + '1 day'::interval ) AND ("endDateParam" + '1 day'::interval ) <= "endDate"
)
SELECT max("endDateParam") FROM prep
) AS "endDateNew"
FROM "somePeriods" AS od
)
SELECT * FROM "maxRecursiveEndDate";
これが実際に何をしているのかは、ここではそれほど重要ではないと思います。重要な点は、RECURSIVE
を含む複数のCTEが関与していることです。
私が試したこと:
my_test_function
なしで試しました。つまり、最初のCTEに直接値を入れました。このようにして、まったく問題はありませんでした。 12と11で同じくらい高速に実行されます。MATERIALIZED
をいじってみましたが、効果がありませんでした。クエリの実行速度は以前と同じです。これが実際にPostgres 12のバグ(またはパフォーマンスの低下)であるのか、ここで何か不足しているのかはわかりません。
付録:再現に使用したDockerコマンド
まず、両方のバージョンのイメージをプルします
docker pull postgres:12.1
docker pull postgres:11.6
次に、Postgres 12を実行します。
docker run -d --name my_postgres_12_container postgres:12.1
次に、クエリを実行します
docker exec my_postgres_12_container psql -U postgres -c "
CREATE OR REPLACE FUNCTION public.my_test_function()
RETURNS SETOF record
LANGUAGE sql
IMMUTABLE SECURITY DEFINER
AS \$function\$
SELECT
1::integer AS id,
'2019-11-20'::date AS \"startDate\",
'2020-01-01'::date AS \"endDate\"
\$function\$;
EXPLAIN ANALYZE WITH \"somePeriods\" AS (
SELECT * FROM my_test_function() AS
f(id integer, \"startDate\" date, \"endDate\" date)
),
\"maxRecursiveEndDate\" AS (
SELECT \"startDate\", \"endDate\", id,
(
WITH RECURSIVE prep(\"startDateParam\", \"endDateParam\") AS (
SELECT \"startDate\",\"endDate\" FROM \"somePeriods\" WHERE id = od.id
UNION
SELECT \"startDate\",\"endDate\" FROM \"somePeriods\", prep
WHERE
\"startDate\" <= (\"endDateParam\" + '1 day'::interval ) AND (\"endDateParam\" + '1 day'::interval ) <= \"endDate\"
)
SELECT max(\"endDateParam\") FROM prep
) AS \"endDateNew\"
FROM \"somePeriods\" AS od
)
SELECT * FROM \"maxRecursiveEndDate\";
"
Postgres 12コンテナを停止します
docker stop my_postgres_12_container
比較のためにPostgres 11を起動します
docker run -d --name my_postgres_11_container postgres:11.6
Postgres 11でクエリを実行する
docker exec my_postgres_11_container psql -U postgres -c "
CREATE OR REPLACE FUNCTION public.my_test_function()
RETURNS SETOF record
LANGUAGE sql
IMMUTABLE SECURITY DEFINER
AS \$function\$
SELECT
1::integer AS id,
'2019-11-20'::date AS \"startDate\",
'2020-01-01'::date AS \"endDate\"
\$function\$;
EXPLAIN ANALYZE WITH \"somePeriods\" AS (
SELECT * FROM my_test_function() AS
f(id integer, \"startDate\" date, \"endDate\" date)
),
\"maxRecursiveEndDate\" AS (
SELECT \"startDate\", \"endDate\", id,
(
WITH RECURSIVE prep(\"startDateParam\", \"endDateParam\") AS (
SELECT \"startDate\",\"endDate\" FROM \"somePeriods\" WHERE id = od.id
UNION
SELECT \"startDate\",\"endDate\" FROM \"somePeriods\", prep
WHERE
\"startDate\" <= (\"endDateParam\" + '1 day'::interval ) AND (\"endDateParam\" + '1 day'::interval ) <= \"endDate\"
)
SELECT max(\"endDateParam\") FROM prep
) AS \"endDateNew\"
FROM \"somePeriods\" AS od
)
SELECT * FROM \"maxRecursiveEndDate\";
"
Pgbugsメーリングリストの関係者のおかげで、Just-in-time-compilation(役立つ背景情報が見つかります here )がPostgreSQL 12でデフォルトでオンになっていることがわかった問題。
SET jit = off;
を使用してクエリを実行すると、問題が解決しました。それがないと、クエリは正常に高速に実行されます。