BUG #5673: Optimizer creates strange execution plan leading to wrong results

Started by David Schmittover 15 years ago6 messagesbugs
Jump to latest
#1David Schmitt
david@dasz.at

The following bug has been logged online:

Bug reference: 5673
Logged by: David Schmitt
Email address: david@dasz.at
PostgreSQL version: 8.4.4
Operating system: Windows 7
Description: Optimizer creates strange execution plan leading to
wrong results
Details:

Background: The following statement is a slightly modfied version of a
statement created by the Entity Framework OR-Mapper when doing a specific
query involving the DefaultPropertyValues base class and the three child
classes CurrentDateTimeDefaultValues, NewGuidDefaultValues,
EnumDefaultValues. There are 60 unique rows in DefaultProperty Values, each
of which is referenced by exactly one row in either
CurrentDateTimeDefaultValues(5 rows), NewGuidDefaultValues(54 rows), or
EnumDefaultValues (1 row). All tables have an ID column and appropriate
PK/FK constraints modeling the inheritance.

Analysis: In the first case the optimizer creates a single Append operation
for the three sequential table scans (lines 10-13) and creates an additional
Index Scan on EnumDefaultValues (lines 14,15) which results in 61 rows
returned in 09. Particularily suspicious are the tow references to the
Extent5 alias on lines 13 and 14. In the second run, I dropped the primary
key on EnumDefaultValues. Now the Append on line 09 returns 60 rows and the
execution plan references EnumDefaultValues only once.

select *
from "dbo"."DefaultPropertyValues" AS "Extent1"
INNER JOIN "dbo"."DefaultPropertyValues" AS "Extent2" ON
"Extent1"."ID"="Extent2"."ID"
LEFT JOIN (
SELECT "UnionAll1"."ID" AS "C1","UnionAll1"."C1" AS "C2","UnionAll1"."C2"
AS "C3","UnionAll1"."C3" AS "C4","UnionAll1"."C4" AS "fk_EnumVal" FROM (
SELECT "Extent3"."ID" AS "ID",TRUE AS "C1",FALSE AS "C2",FALSE AS
"C3",CAST (NULL AS int4) AS "C4"
FROM "dbo"."CurrentDateTimeDefaultValues" AS "Extent3"
UNION ALL
SELECT "Extent4"."ID" AS "ID", TRUE AS "C1",FALSE AS "C2",TRUE AS
"C3",CAST (NULL AS int4) AS "C4"
FROM "dbo"."NewGuidDefaultValues" AS "Extent4") AS "UnionAll1"
UNION ALL
SELECT "Extent5"."ID" AS "ID",FALSE AS "C1",TRUE AS "C2",FALSE AS
"C3","Extent5"."fk_EnumValue" AS "fk_EnumValue"
FROM "dbo"."EnumDefaultValues" AS "Extent5") AS "UnionAll2"
ON "Extent2"."ID"="UnionAll2"."C1"
WHERE ("Extent1"."fk_Property" IS NOT NULL ) AND ("Extent1"."fk_Property"=
(((783))))

Result:
60;"2010-09-20 13:22:17.773308";"2010-09-20
13:22:17.773308";"ecbd6901-13e8-4beb-a6a2-0548eba345a8";;;783;60;"2010-09-20
13:22:17.773308";"2010-09-20
13:22:17.773308";"ecbd6901-13e8-4beb-a6a2-0548eba345a8";;;783;60;f;t;f;3
60;"2010-09-20 13:22:17.773308";"2010-09-20
13:22:17.773308";"ecbd6901-13e8-4beb-a6a2-0548eba345a8";;;783;60;"2010-09-20
13:22:17.773308";"2010-09-20
13:22:17.773308";"ecbd6901-13e8-4beb-a6a2-0548eba345a8";;;783;60;f;t;f;3

EXPLAIN ANALYZE:
01 "Nested Loop Left Join (cost=1.76..7.42 rows=1 width=100) (actual
time=0.121..0.134 rows=2 loops=1)"
02 " Join Filter: ("Extent2"."ID" = "Extent3"."ID")"
03 " -> Hash Join (cost=1.76..3.60 rows=1 width=96) (actual
time=0.061..0.061 rows=1 loops=1)"
04 " Hash Cond: ("Extent2"."ID" = "Extent1"."ID")"
05 " -> Seq Scan on "DefaultPropertyValues" "Extent2"
(cost=0.00..1.60 rows=60 width=48) (actual time=0.008..0.013 rows=60
loops=1)"
06 " -> Hash (cost=1.75..1.75 rows=1 width=48) (actual
time=0.025..0.025 rows=1 loops=1)"
07 " -> Seq Scan on "DefaultPropertyValues" "Extent1"
(cost=0.00..1.75 rows=1 width=48) (actual time=0.023..0.024 rows=1
loops=1)"
08 " Filter: (("fk_Property" IS NOT NULL) AND
("fk_Property" = 783))"
09 " -> Append (cost=0.00..4.07 rows=61 width=11) (actual
time=0.005..0.046 rows=61 loops=1)"
10 " -> Append (cost=0.00..3.60 rows=60 width=11) (actual
time=0.004..0.028 rows=60 loops=1)"
11 " -> Seq Scan on "CurrentDateTimeDefaultValues" "Extent3"
(cost=0.00..1.05 rows=5 width=11) (actual time=0.004..0.005 rows=5
loops=1)"
12 " -> Seq Scan on "NewGuidDefaultValues" "Extent4"
(cost=0.00..1.54 rows=54 width=11) (actual time=0.002..0.014 rows=54
loops=1)"
13 " -> Seq Scan on "EnumDefaultValues" "Extent5"
(cost=0.00..1.01 rows=1 width=11) (actual time=0.002..0.002 rows=1
loops=1)"
14 " -> Index Scan using "PK_[zbox].[dbo].[EnumDefaultValues]" on
"EnumDefaultValues" "Extent5" (cost=0.00..0.47 rows=1 width=11) (actual
time=0.009..0.010 rows=1 loops=1)"
15 " Index Cond: ("Extent2"."ID" = "Extent5"."ID")"
16 "Total runtime: 0.258 ms"

Result:
60;"2010-09-20 13:22:17.773308";"2010-09-20
13:22:17.773308";"ecbd6901-13e8-4beb-a6a2-0548eba345a8";;;783;60;"2010-09-20
13:22:17.773308";"2010-09-20
13:22:17.773308";"ecbd6901-13e8-4beb-a6a2-0548eba345a8";;;783;60;f;t;f;3

EXPLAIN ANALYZE:
01 "Nested Loop Left Join (cost=1.76..7.95 rows=1 width=100) (actual
time=0.109..0.111 rows=1 loops=1)"
02 " Join Filter: ("Extent2"."ID" = "Extent3"."ID")"
03 " -> Hash Join (cost=1.76..3.60 rows=1 width=96) (actual
time=0.057..0.058 rows=1 loops=1)"
04 " Hash Cond: ("Extent2"."ID" = "Extent1"."ID")"
05 " -> Seq Scan on "DefaultPropertyValues" "Extent2"
(cost=0.00..1.60 rows=60 width=48) (actual time=0.006..0.011 rows=60
loops=1)"
06 " -> Hash (cost=1.75..1.75 rows=1 width=48) (actual
time=0.024..0.024 rows=1 loops=1)"
07 " -> Seq Scan on "DefaultPropertyValues" "Extent1"
(cost=0.00..1.75 rows=1 width=48) (actual time=0.022..0.023 rows=1
loops=1)"
08 " Filter: (("fk_Property" IS NOT NULL) AND
("fk_Property" = 783))"
09 " -> Append (cost=0.00..3.60 rows=60 width=11) (actual
time=0.004..0.027 rows=60 loops=1)"
10 " -> Seq Scan on "CurrentDateTimeDefaultValues" "Extent3"
(cost=0.00..1.05 rows=5 width=11) (actual time=0.003..0.005 rows=5
loops=1)"
11 " -> Seq Scan on "NewGuidDefaultValues" "Extent4"
(cost=0.00..1.54 rows=54 width=11) (actual time=0.002..0.014 rows=54
loops=1)"
12 " -> Seq Scan on "EnumDefaultValues" "Extent5" (cost=0.00..1.01
rows=1 width=11) (actual time=0.002..0.002 rows=1 loops=1)"
13 "Total runtime: 0.214 ms"

Other versions:

Postgresql 8.3.11-0lenny1 on Debian lenny does not exhibit this problem.
The backported 8.4.4-1~bpo50+1 for lenny does exhibit the problem.

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Schmitt (#1)
Re: BUG #5673: Optimizer creates strange execution plan leading to wrong results

"David Schmitt" <david@dasz.at> writes:

Description: Optimizer creates strange execution plan leading to
wrong results

Please supply a self-contained example demonstrating the incorrect results.
The information you've provided is completely inadequate for
investigating this problem report. A SQL script that creates some test
tables and executes a query that gives wrong answers would be helpful.

regards, tom lane

#3David Schmitt
david@dasz.at
In reply to: Tom Lane (#2)
Re: BUG #5673: Optimizer creates strange execution plan leading to wrong results

On 9/23/2010 5:33 PM, Tom Lane wrote:

"David Schmitt"<david@dasz.at> writes:

Description: Optimizer creates strange execution plan leading to
wrong results

Please supply a self-contained example demonstrating the incorrect results.
The information you've provided is completely inadequate for
investigating this problem report. A SQL script that creates some test
tables and executes a query that gives wrong answers would be helpful.

Executing the attached example.sql on a fresh database demonstrates the
problem I'm seeing:

postgres@db:~$ dropdb test; createdb test; psql test < example.sql

[load dump]
[execute query]

ID | CreatedOn | ChangedOn | ExportGuid | fk_CreatedBy | fk_ChangedBy | fk_Property | ID | CreatedOn | ChangedOn | ExportGuid | fk_CreatedBy | fk_ChangedBy | fk_Property | C1 | C2 | C3 | C4 | fk_EnumVal
----+----------------------------+----------------------------+--------------------------------------+--------------+--------------+-------------+----+----------------------------+----------------------------+--------------------------------------+--------------+--------------+-------------+----+----+----+----+------------
60 | 2010-09-20 13:22:17.773308 | 2010-09-20 13:22:17.773308 | ecbd6901-13e8-4beb-a6a2-0548eba345a8 | | | 783 | 60 | 2010-09-20 13:22:17.773308 | 2010-09-20 13:22:17.773308 | ecbd6901-13e8-4beb-a6a2-0548eba345a8 | | | 783 | 60 | f | t | f | 3
60 | 2010-09-20 13:22:17.773308 | 2010-09-20 13:22:17.773308 | ecbd6901-13e8-4beb-a6a2-0548eba345a8 | | | 783 | 60 | 2010-09-20 13:22:17.773308 | 2010-09-20 13:22:17.773308 | ecbd6901-13e8-4beb-a6a2-0548eba345a8 | | | 783 | 60 | f | t | f | 3
(2 rows)

[remove pk]
[execute query again]

ALTER TABLE
ID | CreatedOn | ChangedOn | ExportGuid | fk_CreatedBy | fk_ChangedBy | fk_Property | ID | CreatedOn | ChangedOn | ExportGuid | fk_CreatedBy | fk_ChangedBy | fk_Property | C1 | C2 | C3 | C4 | fk_EnumVal
----+----------------------------+----------------------------+--------------------------------------+--------------+--------------+-------------+----+----------------------------+----------------------------+--------------------------------------+--------------+--------------+-------------+----+----+----+----+------------
60 | 2010-09-20 13:22:17.773308 | 2010-09-20 13:22:17.773308 | ecbd6901-13e8-4beb-a6a2-0548eba345a8 | | | 783 | 60 | 2010-09-20 13:22:17.773308 | 2010-09-20 13:22:17.773308 | ecbd6901-13e8-4beb-a6a2-0548eba345a8 | | | 783 | 60 | f | t | f | 3
(1 row)

Hopefully, this helps you debugging it! Thanks for your time and work on
the otherwise really great PostgreSQL.

Best Regards, David
--
dasz.at OG Tel: +43 (0)664 2602670 Web: http://dasz.at
Klosterneuburg UID: ATU64260999

FB-Nr.: FN 309285 g FB-Gericht: LG Korneuburg

Attachments:

example.sqltext/plain; name=example.sqlDownload
#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Schmitt (#3)
Re: BUG #5673: Optimizer creates strange execution plan leading to wrong results

David Schmitt <david@dasz.at> writes:

On 9/23/2010 5:33 PM, Tom Lane wrote:

Please supply a self-contained example demonstrating the incorrect results.

Executing the attached example.sql on a fresh database demonstrates the
problem I'm seeing:

Yup, it sure does. Looking for the cause now. Thanks for the report!

regards, tom lane

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Schmitt (#3)
Re: BUG #5673: Optimizer creates strange execution plan leading to wrong results

David Schmitt <david@dasz.at> writes:

Executing the attached example.sql on a fresh database demonstrates the
problem I'm seeing:

Found it. If you need a patch right away, it's a one-liner:

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 2d86da3..b7cf0b8 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -425,7 +425,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		childpath = childrel->cheapest_total_path;
 		if (IsA(childpath, AppendPath))
 			subpaths = list_concat(subpaths,
-								   ((AppendPath *) childpath)->subpaths);
+							list_copy(((AppendPath *) childpath)->subpaths));
 		else
 			subpaths = lappend(subpaths, childpath);

regards, tom lane

#6David Schmitt
david@dasz.at
In reply to: Tom Lane (#5)
Re: BUG #5673: Optimizer creates strange execution plan leading to wrong results

On 9/23/2010 9:53 PM, Tom Lane wrote:

David Schmitt<david@dasz.at> writes:

Executing the attached example.sql on a fresh database demonstrates the
problem I'm seeing:

Found it. If you need a patch right away, it's a one-liner:

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 2d86da3..b7cf0b8 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -425,7 +425,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
childpath = childrel->cheapest_total_path;
if (IsA(childpath, AppendPath))
subpaths = list_concat(subpaths,
-								   ((AppendPath *) childpath)->subpaths);
+							list_copy(((AppendPath *) childpath)->subpaths));
else
subpaths = lappend(subpaths, childpath);

Thank you very very much, you made my day! *phew*

Best Regards, David
--
dasz.at OG Tel: +43 (0)664 2602670 Web: http://dasz.at
Klosterneuburg UID: ATU64260999

FB-Nr.: FN 309285 g FB-Gericht: LG Korneuburg