Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf6daa91

Browse files
committed
Enhance partition pruning for an array parameter.
It is designed to prune partitions in case when incoming clause looks likethe following: 'partkey = ANY($1)'.It seems quite a common case when the array is a parameter of a function.Although the code is covered by tests the code should be carefully reviewed andtested.
1 parenta359d37 commitf6daa91

File tree

3 files changed

+311
-4
lines changed

3 files changed

+311
-4
lines changed

‎src/backend/partitioning/partprune.c

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,6 +2179,9 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
21792179
List*elem_exprs,
21802180
*elem_clauses;
21812181
ListCell*lc1;
2182+
intstrategy;
2183+
Oidlefttype,
2184+
righttype;
21822185

21832186
if (IsA(leftop,RelabelType))
21842187
leftop= ((RelabelType*)leftop)->arg;
@@ -2206,10 +2209,6 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
22062209
negator=get_negator(saop_op);
22072210
if (OidIsValid(negator)&&op_in_opfamily(negator,partopfamily))
22082211
{
2209-
intstrategy;
2210-
Oidlefttype,
2211-
righttype;
2212-
22132212
get_op_opfamily_properties(negator,partopfamily,
22142213
false,&strategy,
22152214
&lefttype,&righttype);
@@ -2219,6 +2218,12 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
22192218
else
22202219
returnPARTCLAUSE_NOMATCH;/* no useful negator */
22212220
}
2221+
else
2222+
{
2223+
get_op_opfamily_properties(saop_op,partopfamily, false,
2224+
&strategy,&lefttype,
2225+
&righttype);
2226+
}
22222227

22232228
/*
22242229
* Only allow strict operators. This will guarantee nulls are
@@ -2365,6 +2370,64 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
23652370
*/
23662371
elem_exprs=arrexpr->elements;
23672372
}
2373+
elseif (IsA(rightop,Param))
2374+
{
2375+
Oidcmpfn;
2376+
PartClauseInfo*partclause;
2377+
2378+
if (righttype==part_scheme->partopcintype[partkeyidx])
2379+
cmpfn=part_scheme->partsupfunc[partkeyidx].fn_oid;
2380+
else
2381+
{
2382+
switch (part_scheme->strategy)
2383+
{
2384+
/*
2385+
* For range and list partitioning, we need the ordering
2386+
* procedure with lefttype being the partition key's type,
2387+
* and righttype the clause's operator's right type.
2388+
*/
2389+
casePARTITION_STRATEGY_LIST:
2390+
casePARTITION_STRATEGY_RANGE:
2391+
cmpfn=
2392+
get_opfamily_proc(part_scheme->partopfamily[partkeyidx],
2393+
part_scheme->partopcintype[partkeyidx],
2394+
righttype,BTORDER_PROC);
2395+
break;
2396+
2397+
/*
2398+
* For hash partitioning, we need the hashing procedure
2399+
* for the clause's type.
2400+
*/
2401+
casePARTITION_STRATEGY_HASH:
2402+
cmpfn=
2403+
get_opfamily_proc(part_scheme->partopfamily[partkeyidx],
2404+
righttype,righttype,
2405+
HASHEXTENDED_PROC);
2406+
break;
2407+
2408+
default:
2409+
elog(ERROR,"invalid partition strategy: %c",
2410+
part_scheme->strategy);
2411+
cmpfn=InvalidOid;/* keep compiler quiet */
2412+
break;
2413+
}
2414+
2415+
if (!OidIsValid(cmpfn))
2416+
returnPARTCLAUSE_NOMATCH;
2417+
}
2418+
2419+
partclause= (PartClauseInfo*)palloc(sizeof(PartClauseInfo));
2420+
partclause->keyno=partkeyidx;
2421+
partclause->opno=saop_op;
2422+
partclause->op_is_ne= false;
2423+
partclause->op_strategy=strategy;
2424+
partclause->expr=rightop;
2425+
partclause->cmpfn=cmpfn;
2426+
2427+
*pc=partclause;
2428+
2429+
returnPARTCLAUSE_MATCH_CLAUSE;
2430+
}
23682431
else
23692432
{
23702433
/* Give up on any other clause types. */

‎src/test/regress/expected/inherit.out

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3823,3 +3823,183 @@ select * from tuplesest_tab join
38233823

38243824
drop table tuplesest_parted;
38253825
drop table tuplesest_tab;
3826+
--
3827+
-- Test the cases for partition pruning by an expression like:
3828+
-- partkey = ANY($1)
3829+
--
3830+
CREATE TABLE array_prune (id int)
3831+
PARTITION BY HASH(id);
3832+
CREATE TABLE array_prune_t0
3833+
PARTITION OF array_prune FOR VALUES WITH (modulus 2, remainder 0);
3834+
CREATE TABLE array_prune_t1
3835+
PARTITION OF array_prune FOR VALUES WITH (modulus 2, remainder 1);
3836+
CREATE FUNCTION array_prune_fn(oper text, arr text) RETURNS setof text
3837+
LANGUAGE plpgsql AS $$
3838+
DECLARE
3839+
line text;
3840+
query text;
3841+
BEGIN
3842+
query := format('EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id %s (%s)', $1, $2);
3843+
FOR line IN EXECUTE query
3844+
LOOP
3845+
RETURN NEXT line;
3846+
END LOOP;
3847+
END; $$;
3848+
SELECT array_prune_fn('= ANY', 'ARRAY[1]'); -- prune one partition
3849+
array_prune_fn
3850+
-----------------------------------------
3851+
Seq Scan on array_prune_t0 array_prune
3852+
Filter: (id = ANY ('{1}'::integer[]))
3853+
(2 rows)
3854+
3855+
SELECT array_prune_fn('= ANY', 'ARRAY[1,2]'); -- prune one partition
3856+
array_prune_fn
3857+
-------------------------------------------
3858+
Seq Scan on array_prune_t0 array_prune
3859+
Filter: (id = ANY ('{1,2}'::integer[]))
3860+
(2 rows)
3861+
3862+
SELECT array_prune_fn('= ANY', 'ARRAY[1,2,3]'); -- no pruning
3863+
array_prune_fn
3864+
---------------------------------------------------
3865+
Append
3866+
-> Seq Scan on array_prune_t0 array_prune_1
3867+
Filter: (id = ANY ('{1,2,3}'::integer[]))
3868+
-> Seq Scan on array_prune_t1 array_prune_2
3869+
Filter: (id = ANY ('{1,2,3}'::integer[]))
3870+
(5 rows)
3871+
3872+
SELECT array_prune_fn('= ANY', 'ARRAY[1, NULL]'); -- prune
3873+
array_prune_fn
3874+
----------------------------------------------
3875+
Seq Scan on array_prune_t0 array_prune
3876+
Filter: (id = ANY ('{1,NULL}'::integer[]))
3877+
(2 rows)
3878+
3879+
SELECT array_prune_fn('= ANY', 'ARRAY[3, NULL]'); -- prune
3880+
array_prune_fn
3881+
----------------------------------------------
3882+
Seq Scan on array_prune_t1 array_prune
3883+
Filter: (id = ANY ('{3,NULL}'::integer[]))
3884+
(2 rows)
3885+
3886+
SELECT array_prune_fn('= ANY', 'ARRAY[NULL, NULL]'); -- error
3887+
ERROR: operator does not exist: integer = text
3888+
LINE 1: ...IN (COSTS OFF) SELECT * FROM array_prune WHERE id = ANY (ARR...
3889+
^
3890+
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
3891+
QUERY: EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id = ANY (ARRAY[NULL, NULL])
3892+
CONTEXT: PL/pgSQL function array_prune_fn(text,text) line 7 at FOR over EXECUTE statement
3893+
-- Check case of explicit cast
3894+
SELECT array_prune_fn('= ANY', 'ARRAY[1,2]::numeric[]');
3895+
array_prune_fn
3896+
------------------------------------------------------------
3897+
Append
3898+
-> Seq Scan on array_prune_t0 array_prune_1
3899+
Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3900+
-> Seq Scan on array_prune_t1 array_prune_2
3901+
Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3902+
(5 rows)
3903+
3904+
SELECT array_prune_fn('= ANY', 'ARRAY[1::bigint,2::int]'); -- conversion to bigint
3905+
array_prune_fn
3906+
------------------------------------------
3907+
Seq Scan on array_prune_t0 array_prune
3908+
Filter: (id = ANY ('{1,2}'::bigint[]))
3909+
(2 rows)
3910+
3911+
SELECT array_prune_fn('= ANY', 'ARRAY[1::bigint,2::numeric]'); -- conversion to numeric
3912+
array_prune_fn
3913+
------------------------------------------------------------
3914+
Append
3915+
-> Seq Scan on array_prune_t0 array_prune_1
3916+
Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3917+
-> Seq Scan on array_prune_t1 array_prune_2
3918+
Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3919+
(5 rows)
3920+
3921+
SELECT array_prune_fn('= ANY', 'ARRAY[1::bigint,2::text]'); -- Error. XXX: slightly different error in comparison with the static case
3922+
ERROR: ARRAY types bigint and text cannot be matched
3923+
LINE 1: ...* FROM array_prune WHERE id = ANY (ARRAY[1::bigint,2::text])
3924+
^
3925+
QUERY: EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id = ANY (ARRAY[1::bigint,2::text])
3926+
CONTEXT: PL/pgSQL function array_prune_fn(text,text) line 7 at FOR over EXECUTE statement
3927+
SELECT array_prune_fn('<> ANY', 'ARRAY[1]'); -- no pruning
3928+
array_prune_fn
3929+
------------------------------------------------
3930+
Append
3931+
-> Seq Scan on array_prune_t0 array_prune_1
3932+
Filter: (id <> ANY ('{1}'::integer[]))
3933+
-> Seq Scan on array_prune_t1 array_prune_2
3934+
Filter: (id <> ANY ('{1}'::integer[]))
3935+
(5 rows)
3936+
3937+
DROP TABLE IF EXISTS array_prune CASCADE;
3938+
CREATE TABLE array_prune (id int)
3939+
PARTITION BY RANGE(id);
3940+
CREATE TABLE array_prune_t0
3941+
PARTITION OF array_prune FOR VALUES FROM (1) TO (10);
3942+
CREATE TABLE array_prune_t1
3943+
PARTITION OF array_prune FOR VALUES FROM (10) TO (20);
3944+
SELECT array_prune_fn('= ANY', 'ARRAY[10]'); -- prune
3945+
array_prune_fn
3946+
------------------------------------------
3947+
Seq Scan on array_prune_t1 array_prune
3948+
Filter: (id = ANY ('{10}'::integer[]))
3949+
(2 rows)
3950+
3951+
SELECT array_prune_fn('>= ANY', 'ARRAY[10]'); -- prune
3952+
array_prune_fn
3953+
-------------------------------------------
3954+
Seq Scan on array_prune_t1 array_prune
3955+
Filter: (id >= ANY ('{10}'::integer[]))
3956+
(2 rows)
3957+
3958+
SELECT array_prune_fn('>= ANY', 'ARRAY[9, 10]'); -- do not prune
3959+
array_prune_fn
3960+
---------------------------------------------------
3961+
Append
3962+
-> Seq Scan on array_prune_t0 array_prune_1
3963+
Filter: (id >= ANY ('{9,10}'::integer[]))
3964+
-> Seq Scan on array_prune_t1 array_prune_2
3965+
Filter: (id >= ANY ('{9,10}'::integer[]))
3966+
(5 rows)
3967+
3968+
DROP TABLE IF EXISTS array_prune CASCADE;
3969+
CREATE TABLE array_prune (id int)
3970+
PARTITION BY LIST(id);
3971+
CREATE TABLE array_prune_t0
3972+
PARTITION OF array_prune FOR VALUES IN ('1');
3973+
CREATE TABLE array_prune_t1
3974+
PARTITION OF array_prune FOR VALUES IN ('2');
3975+
SELECT array_prune_fn('= ANY', 'ARRAY[1,1]'); -- prune second
3976+
array_prune_fn
3977+
-------------------------------------------
3978+
Seq Scan on array_prune_t0 array_prune
3979+
Filter: (id = ANY ('{1,1}'::integer[]))
3980+
(2 rows)
3981+
3982+
SELECT array_prune_fn('>= ANY', 'ARRAY[1,2]'); -- do not prune
3983+
array_prune_fn
3984+
--------------------------------------------------
3985+
Append
3986+
-> Seq Scan on array_prune_t0 array_prune_1
3987+
Filter: (id >= ANY ('{1,2}'::integer[]))
3988+
-> Seq Scan on array_prune_t1 array_prune_2
3989+
Filter: (id >= ANY ('{1,2}'::integer[]))
3990+
(5 rows)
3991+
3992+
SELECT array_prune_fn('<> ANY', 'ARRAY[1]'); -- prune second
3993+
array_prune_fn
3994+
------------------------------------------
3995+
Seq Scan on array_prune_t1 array_prune
3996+
Filter: (id <> ANY ('{1}'::integer[]))
3997+
(2 rows)
3998+
3999+
SELECT array_prune_fn('<> ALL', 'ARRAY[1,2]'); -- prune both
4000+
array_prune_fn
4001+
--------------------------
4002+
Result
4003+
One-Time Filter: false
4004+
(2 rows)
4005+

‎src/test/regress/sql/inherit.sql

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,3 +1581,67 @@ select * from tuplesest_tab join
15811581

15821582
droptable tuplesest_parted;
15831583
droptable tuplesest_tab;
1584+
1585+
--
1586+
-- Test the cases for partition pruning by an expression like:
1587+
-- partkey = ANY($1)
1588+
--
1589+
1590+
CREATETABLEarray_prune (idint)
1591+
PARTITION BY HASH(id);
1592+
1593+
CREATETABLEarray_prune_t0
1594+
PARTITION OF array_prune FORVALUES WITH (modulus2, remainder0);
1595+
CREATETABLEarray_prune_t1
1596+
PARTITION OF array_prune FORVALUES WITH (modulus2, remainder1);
1597+
1598+
CREATEFUNCTIONarray_prune_fn(opertext, arrtext) RETURNS setoftext
1599+
LANGUAGE plpgsqlAS $$
1600+
DECLARE
1601+
linetext;
1602+
querytext;
1603+
BEGIN
1604+
query := format('EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id %s (%s)', $1, $2);
1605+
FORlineIN EXECUTE query
1606+
LOOP
1607+
RETURN NEXTline;
1608+
END LOOP;
1609+
END; $$;
1610+
1611+
SELECT array_prune_fn('= ANY','ARRAY[1]');-- prune one partition
1612+
SELECT array_prune_fn('= ANY','ARRAY[1,2]');-- prune one partition
1613+
SELECT array_prune_fn('= ANY','ARRAY[1,2,3]');-- no pruning
1614+
SELECT array_prune_fn('= ANY','ARRAY[1, NULL]');-- prune
1615+
SELECT array_prune_fn('= ANY','ARRAY[3, NULL]');-- prune
1616+
SELECT array_prune_fn('= ANY','ARRAY[NULL, NULL]');-- error
1617+
-- Check case of explicit cast
1618+
SELECT array_prune_fn('= ANY','ARRAY[1,2]::numeric[]');
1619+
SELECT array_prune_fn('= ANY','ARRAY[1::bigint,2::int]');-- conversion to bigint
1620+
SELECT array_prune_fn('= ANY','ARRAY[1::bigint,2::numeric]');-- conversion to numeric
1621+
SELECT array_prune_fn('= ANY','ARRAY[1::bigint,2::text]');-- Error. XXX: slightly different error in comparison with the static case
1622+
1623+
SELECT array_prune_fn('<> ANY','ARRAY[1]');-- no pruning
1624+
1625+
DROPTABLE IF EXISTS array_prune CASCADE;
1626+
CREATETABLEarray_prune (idint)
1627+
PARTITION BY RANGE(id);
1628+
CREATETABLEarray_prune_t0
1629+
PARTITION OF array_prune FORVALUESFROM (1) TO (10);
1630+
CREATETABLEarray_prune_t1
1631+
PARTITION OF array_prune FORVALUESFROM (10) TO (20);
1632+
1633+
SELECT array_prune_fn('= ANY','ARRAY[10]');-- prune
1634+
SELECT array_prune_fn('>= ANY','ARRAY[10]');-- prune
1635+
SELECT array_prune_fn('>= ANY','ARRAY[9, 10]');-- do not prune
1636+
1637+
DROPTABLE IF EXISTS array_prune CASCADE;
1638+
CREATETABLEarray_prune (idint)
1639+
PARTITION BY LIST(id);
1640+
CREATETABLEarray_prune_t0
1641+
PARTITION OF array_prune FORVALUESIN ('1');
1642+
CREATETABLEarray_prune_t1
1643+
PARTITION OF array_prune FORVALUESIN ('2');
1644+
SELECT array_prune_fn('= ANY','ARRAY[1,1]');-- prune second
1645+
SELECT array_prune_fn('>= ANY','ARRAY[1,2]');-- do not prune
1646+
SELECT array_prune_fn('<> ANY','ARRAY[1]');-- prune second
1647+
SELECT array_prune_fn('<> ALL','ARRAY[1,2]');-- prune both

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp