Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c238442

Browse files
committed
Micro-optimize some slower queries in the opr_sanity regression test.
Convert the binary_coercible() and physically_coercible() functions from SQL to plpgsql. It's not that plpgsql is inherently better at doing queries; if you simply convert the previous single SQL query into one RETURN expression, it's no faster. The problem with the existing code is that it fools the plancache into deciding that it's worth re-planning the query every time, since constant-folding with a concrete value for $2 allows elimination of at least one sub-SELECT. In reality that's using the planner to do the equivalent of a few runtime boolean tests, causing the function to run much slower than it should. Splitting the AND/OR logic into separate plpgsql statements allows each if-expression to acquire a static plan. Also, get rid of some uses of obj_description() in favor of explicitly joining to pg_description, allowing the joins to be optimized better. (Someday we might improve the SQL-function-inlining logic enough that this happens automatically, but today is not that day.) Together, these changes reduce the runtime of the opr_sanity regression test by about a factor of two on one of my slower machines. They don't seem to help as much on a fast machine, but this should at least benefit the buildfarm.
1 parent bc920be commit c238442

File tree

2 files changed

+100
-52
lines changed

2 files changed

+100
-52
lines changed

src/test/regress/expected/opr_sanity.out

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,47 @@
2020
-- allowed.
2121
-- This should match IsBinaryCoercible() in parse_coerce.c.
2222
create function binary_coercible(oid, oid) returns bool as $$
23-
SELECT ($1 = $2) OR
24-
EXISTS(select 1 from pg_catalog.pg_cast where
25-
castsource = $1 and casttarget = $2 and
26-
castmethod = 'b' and castcontext = 'i') OR
27-
($2 = 'pg_catalog.any'::pg_catalog.regtype) OR
28-
($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
29-
EXISTS(select 1 from pg_catalog.pg_type where
30-
oid = $1 and typelem != 0 and typlen = -1)) OR
31-
($2 = 'pg_catalog.anyrange'::pg_catalog.regtype AND
32-
(select typtype from pg_catalog.pg_type where oid = $1) = 'r')
33-
$$ language sql strict stable;
23+
begin
24+
if $1 = $2 then return true; end if;
25+
if EXISTS(select 1 from pg_catalog.pg_cast where
26+
castsource = $1 and casttarget = $2 and
27+
castmethod = 'b' and castcontext = 'i')
28+
then return true; end if;
29+
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
30+
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
31+
if EXISTS(select 1 from pg_catalog.pg_type where
32+
oid = $1 and typelem != 0 and typlen = -1)
33+
then return true; end if;
34+
end if;
35+
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
36+
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
37+
then return true; end if;
38+
end if;
39+
return false;
40+
end
41+
$$ language plpgsql strict stable;
3442
-- This one ignores castcontext, so it considers only physical equivalence
3543
-- and not whether the coercion can be invoked implicitly.
3644
create function physically_coercible(oid, oid) returns bool as $$
37-
SELECT ($1 = $2) OR
38-
EXISTS(select 1 from pg_catalog.pg_cast where
39-
castsource = $1 and casttarget = $2 and
40-
castmethod = 'b') OR
41-
($2 = 'pg_catalog.any'::pg_catalog.regtype) OR
42-
($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
43-
EXISTS(select 1 from pg_catalog.pg_type where
44-
oid = $1 and typelem != 0 and typlen = -1)) OR
45-
($2 = 'pg_catalog.anyrange'::pg_catalog.regtype AND
46-
(select typtype from pg_catalog.pg_type where oid = $1) = 'r')
47-
$$ language sql strict stable;
45+
begin
46+
if $1 = $2 then return true; end if;
47+
if EXISTS(select 1 from pg_catalog.pg_cast where
48+
castsource = $1 and casttarget = $2 and
49+
castmethod = 'b')
50+
then return true; end if;
51+
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
52+
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
53+
if EXISTS(select 1 from pg_catalog.pg_type where
54+
oid = $1 and typelem != 0 and typlen = -1)
55+
then return true; end if;
56+
end if;
57+
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
58+
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
59+
then return true; end if;
60+
end if;
61+
return false;
62+
end
63+
$$ language plpgsql strict stable;
4864
-- **************** pg_proc ****************
4965
-- Look for illegal values in pg_proc fields.
5066
SELECT p1.oid, p1.proname
@@ -1190,10 +1206,14 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999;
11901206
-- be called directly; those should have comments matching their operator.
11911207
WITH funcdescs AS (
11921208
SELECT p.oid as p_oid, proname, o.oid as o_oid,
1193-
obj_description(p.oid, 'pg_proc') as prodesc,
1209+
pd.description as prodesc,
11941210
'implementation of ' || oprname || ' operator' as expecteddesc,
1195-
obj_description(o.oid, 'pg_operator') as oprdesc
1211+
od.description as oprdesc
11961212
FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
1213+
LEFT JOIN pg_description pd ON
1214+
(pd.objoid = p.oid and pd.classoid = p.tableoid and pd.objsubid = 0)
1215+
LEFT JOIN pg_description od ON
1216+
(od.objoid = o.oid and od.classoid = o.tableoid and od.objsubid = 0)
11971217
WHERE o.oid <= 9999
11981218
)
11991219
SELECT * FROM funcdescs
@@ -1210,10 +1230,14 @@ SELECT * FROM funcdescs
12101230
-- This should be a pretty short list; it's mostly legacy cases.
12111231
WITH funcdescs AS (
12121232
SELECT p.oid as p_oid, proname, o.oid as o_oid,
1213-
obj_description(p.oid, 'pg_proc') as prodesc,
1233+
pd.description as prodesc,
12141234
'implementation of ' || oprname || ' operator' as expecteddesc,
1215-
obj_description(o.oid, 'pg_operator') as oprdesc
1235+
od.description as oprdesc
12161236
FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
1237+
LEFT JOIN pg_description pd ON
1238+
(pd.objoid = p.oid and pd.classoid = p.tableoid and pd.objsubid = 0)
1239+
LEFT JOIN pg_description od ON
1240+
(od.objoid = o.oid and od.classoid = o.tableoid and od.objsubid = 0)
12171241
WHERE o.oid <= 9999
12181242
)
12191243
SELECT p_oid, proname, prodesc FROM funcdescs

src/test/regress/sql/opr_sanity.sql

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,48 @@
2323

2424
-- This should match IsBinaryCoercible() in parse_coerce.c.
2525
create function binary_coercible(oid, oid) returns bool as $$
26-
SELECT ($1 = $2) OR
27-
EXISTS(select 1 from pg_catalog.pg_cast where
28-
castsource = $1 and casttarget = $2 and
29-
castmethod = 'b' and castcontext = 'i') OR
30-
($2 = 'pg_catalog.any'::pg_catalog.regtype) OR
31-
($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
32-
EXISTS(select 1 from pg_catalog.pg_type where
33-
oid = $1 and typelem != 0 and typlen = -1)) OR
34-
($2 = 'pg_catalog.anyrange'::pg_catalog.regtype AND
35-
(select typtype from pg_catalog.pg_type where oid = $1) = 'r')
36-
$$ language sql strict stable;
26+
begin
27+
if $1 = $2 then return true; end if;
28+
if EXISTS(select 1 from pg_catalog.pg_cast where
29+
castsource = $1 and casttarget = $2 and
30+
castmethod = 'b' and castcontext = 'i')
31+
then return true; end if;
32+
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
33+
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
34+
if EXISTS(select 1 from pg_catalog.pg_type where
35+
oid = $1 and typelem != 0 and typlen = -1)
36+
then return true; end if;
37+
end if;
38+
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
39+
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
40+
then return true; end if;
41+
end if;
42+
return false;
43+
end
44+
$$ language plpgsql strict stable;
3745

3846
-- This one ignores castcontext, so it considers only physical equivalence
3947
-- and not whether the coercion can be invoked implicitly.
4048
create function physically_coercible(oid, oid) returns bool as $$
41-
SELECT ($1 = $2) OR
42-
EXISTS(select 1 from pg_catalog.pg_cast where
43-
castsource = $1 and casttarget = $2 and
44-
castmethod = 'b') OR
45-
($2 = 'pg_catalog.any'::pg_catalog.regtype) OR
46-
($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND
47-
EXISTS(select 1 from pg_catalog.pg_type where
48-
oid = $1 and typelem != 0 and typlen = -1)) OR
49-
($2 = 'pg_catalog.anyrange'::pg_catalog.regtype AND
50-
(select typtype from pg_catalog.pg_type where oid = $1) = 'r')
51-
$$ language sql strict stable;
49+
begin
50+
if $1 = $2 then return true; end if;
51+
if EXISTS(select 1 from pg_catalog.pg_cast where
52+
castsource = $1 and casttarget = $2 and
53+
castmethod = 'b')
54+
then return true; end if;
55+
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
56+
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
57+
if EXISTS(select 1 from pg_catalog.pg_type where
58+
oid = $1 and typelem != 0 and typlen = -1)
59+
then return true; end if;
60+
end if;
61+
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
62+
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
63+
then return true; end if;
64+
end if;
65+
return false;
66+
end
67+
$$ language plpgsql strict stable;
5268

5369

5470
-- **************** pg_proc ****************
@@ -725,10 +741,14 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999;
725741
-- be called directly; those should have comments matching their operator.
726742
WITH funcdescs AS (
727743
SELECT p.oid as p_oid, proname, o.oid as o_oid,
728-
obj_description(p.oid, 'pg_proc') as prodesc,
744+
pd.description as prodesc,
729745
'implementation of ' || oprname || ' operator' as expecteddesc,
730-
obj_description(o.oid, 'pg_operator') as oprdesc
746+
od.description as oprdesc
731747
FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
748+
LEFT JOIN pg_description pd ON
749+
(pd.objoid = p.oid and pd.classoid = p.tableoid and pd.objsubid = 0)
750+
LEFT JOIN pg_description od ON
751+
(od.objoid = o.oid and od.classoid = o.tableoid and od.objsubid = 0)
732752
WHERE o.oid <= 9999
733753
)
734754
SELECT * FROM funcdescs
@@ -742,10 +762,14 @@ SELECT * FROM funcdescs
742762
-- This should be a pretty short list; it's mostly legacy cases.
743763
WITH funcdescs AS (
744764
SELECT p.oid as p_oid, proname, o.oid as o_oid,
745-
obj_description(p.oid, 'pg_proc') as prodesc,
765+
pd.description as prodesc,
746766
'implementation of ' || oprname || ' operator' as expecteddesc,
747-
obj_description(o.oid, 'pg_operator') as oprdesc
767+
od.description as oprdesc
748768
FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid
769+
LEFT JOIN pg_description pd ON
770+
(pd.objoid = p.oid and pd.classoid = p.tableoid and pd.objsubid = 0)
771+
LEFT JOIN pg_description od ON
772+
(od.objoid = o.oid and od.classoid = o.tableoid and od.objsubid = 0)
749773
WHERE o.oid <= 9999
750774
)
751775
SELECT p_oid, proname, prodesc FROM funcdescs

0 commit comments

Comments
 (0)