PostgreSQL Bugs

Collected from the PG bugs email list.

Bug ID16223
PG Version12.1
OSUbuntu 18.04
Opened2020-01-22 06:02:40+00
Reported byChristianS
StatusNew

Body of first available message related to this bug follows.

The following bug has been logged on the website:

Bug reference:      16223
Logged by:          ChristianS
Email address:      (redacted)
PostgreSQL version: 12.1
Operating system:   Ubuntu 18.04
Description:        

I have a query that runs significantly slower in Postgres 12.1 than it does
in Postgres 11.6.

(I have asked on dba.stackexchange
https://dba.stackexchange.com/questions/257759/recursive-cte-based-on-function-values-significantly-slower-on-postgres-12-than
- hoping that someone would jump in and tell me why this is my fault and why
it has nothing to do with PostgreSQL itself. However, since there is still
no reaction after two days, I can be somewhat sure that it's not a very
obvious mistake of mine and maybe something you might want to
investigate.)


First, we create this simple function


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$;


Then for the actual query


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";


What this actually does it not so important here, I guess. The important
point is: It runs very fast on Postgres 11.6 (like ca 4ms) and much slower
on PostgreSQL 12.1 (ca 150ms). The output of EXPLAIN ANALYZE did not give me
further hints.
A crucial point might or might be not, that are multiple CTEs involved,
including a RECURSIVE one. However, that's speculation.

What I tried out:
- I did try without my_test_function, i.e. putting the values directly into
the first CTE without using a function. This way, there was no problem at
all. Like this, it runs equally fast both on 12.1 and on 11.6.
- On Postgres 12, I played around with MATERIALIZED, but could not see any
effect. The query still runs as slow as before.

Note on reproducibility:
I was able to reproduce the phenomenon on various systems: on multiple VMs
in VirtualBox; via Docker on two different physical machines. (See below for
Docker commands.) However, strange enough, I cannot reproduce it on
https://www.db-fiddle.com/ (no difference to be seen there, both are
fast).


Docker commands:

# First, pull images of both versions

docker pull postgres:12.1
docker pull postgres:11.6

# Now, run Postgres 12

docker run -d --name my_postgres_12_container postgres:12.1

# Now, execute the query

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\";
"

# Stop the Postgres 12 container

docker stop my_postgres_12_container

# Start Postgres 11 for comparison

docker run -d --name my_postgres_11_container postgres:11.6

# Execute the query in 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\"

Messages

DateAuthorSubject
2020-01-22 06:02:40+00PG Bug reporting formBUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-27 05:39:54+00Christian SchwadererRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-27 10:20:54+00Daniel GustafssonRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-27 12:46:01+00Christian SchwadererRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-27 15:31:44+00Tom LaneRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-29 13:49:10+00Christian SchwadererRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-29 15:18:51+00Tom LaneRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-01-29 15:31:05+00Kieran McCuskerRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function
2020-02-03 09:15:46+00Andres FreundRe: BUG #16223: Performance regression between 11.6 and 12.1 in an SQL query with a recursive CTE based on function