Skip to content
This repository was archived by the owner on May 24, 2024. It is now read-only.

Commit eeea7f1

Browse files
authored
Optimize MPP FDW LIMIT/OFFSET push down when there is NULL/0. (#17246)
When there are NULL or zero values in OFFSET/LIMIT clause, we do NOT need to fetch more rows and expression NULL plus others is pointless. Optimize (N > 0) LIMIT 0 OFFSET N to LIMIT 0 LIMIT 0 OFFSET NULL to LIMIT 0 LIMIT N OFFSET NULL to LIMIT N LIMIT N OFFSET 0 to LIMIT N Example before this fix: EXPLAIN (VERBOSE, COSTS OFF) SELECT c1, c2 FROM mpp_ft2 order by c1 limit 0 offset 998; QUERY PLAN -------------- Limit Output: c1, c2 -> Gather Motion 2:1 (slice1; segments: 2) Output: c1, c2 Merge Key: c1 -> Foreign Scan on public.mpp_ft2 Output: c1, c2 Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT (998::bigint + 0::bigint) We will have to fetch 998 rows from remote, but as we have limit 0, that's pointless. With this fix: EXPLAIN (VERBOSE, COSTS OFF) SELECT c1, c2 FROM mpp_ft2 order by c1 limit 0 offset 998; QUERY PLAN -------------- Limit Output: c1, c2 -> Gather Motion 2:1 (slice1; segments: 2) Output: c1, c2 Merge Key: c1 -> Foreign Scan on public.mpp_ft2 Output: c1, c2 Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT 0::bigint
1 parent cc09dbd commit eeea7f1

4 files changed

Lines changed: 136 additions & 3 deletions

File tree

contrib/postgres_fdw/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ endif
2727

2828
# For postgres_fdw test
2929
export PG_PORT=5432
30-
installcheck: prep_postgres
30+
installcheck: install prep_postgres
3131
clean: clean_postgres
3232
prep_postgres:
3333
./postgres_setup.bash

contrib/postgres_fdw/deparse.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3544,14 +3544,31 @@ appendLimitClause(deparse_expr_cxt *context)
35443544
* This may reduce the number of tuples that we need to fetch from remote servers.
35453545
*/
35463546
Node *precount = copyObject(root->parse->limitCount);
3547+
Node *offset = copyObject(root->parse->limitOffset);
3548+
bool offset_needed = ((precount != NULL) && (offset != NULL));
35473549

35483550
/*
35493551
* If we've specified both OFFSET and LIMIT clause,
35503552
* it's enough to fetch tuples from 0 to limitCount + limitOffset from remote servers.
3553+
* optimize (N > 0):
3554+
* LIMIT 0 OFFSET N to LIMIT 0
3555+
* LIMIT 0 OFFSET NULL to LIMIT 0
3556+
* LIMIT N OFFSET NULL to LIMIT N
3557+
* LIMIT N OFFSET 0 to LIMIT N
35513558
*/
3559+
if (offset_needed &&
3560+
IsA(precount, Const) &&
3561+
(((Const *) precount)->constisnull || ((Const *) precount)->constvalue == 0))
3562+
offset_needed = false;
3563+
3564+
if (offset_needed &&
3565+
IsA(offset, Const) &&
3566+
(((Const *) offset)->constisnull || ((Const *) offset)->constvalue == 0))
3567+
offset_needed = false;
3568+
35523569
if (precount)
35533570
{
3554-
if (root->parse->limitOffset)
3571+
if (offset_needed)
35553572
{
35563573
ParseState *pstate = make_parsestate(NULL);
35573574
/*
@@ -3560,7 +3577,7 @@ appendLimitClause(deparse_expr_cxt *context)
35603577
*/
35613578
precount = (Node *) make_op(pstate,
35623579
list_make2(makeString("pg_catalog"), makeString(pstrdup("+"))),
3563-
copyObject(root->parse->limitOffset),
3580+
offset,
35643581
precount,
35653582
NULL,
35663583
-1);

contrib/postgres_fdw/expected/mpp_gp2pg_postgres_fdw.out

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,105 @@ SELECT c1, c2 FROM mpp_ft2 order by c1 offset 998;
981981
1000 | 0
982982
(2 rows)
983983

984+
-- test LIMIT 0, OFFSET null/0
985+
ALTER FOREIGN TABLE mpp_ft2 OPTIONS(set use_remote_estimate 'true');
986+
EXPLAIN (VERBOSE, COSTS OFF)
987+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit null offset 998;
988+
QUERY PLAN
989+
------------------------------------------------------------------------------------------------------------
990+
Limit
991+
Output: c1, c2
992+
-> Gather Motion 2:1 (slice1; segments: 2)
993+
Output: c1, c2
994+
Merge Key: c1
995+
-> Foreign Scan on public.mpp_ft2
996+
Output: c1, c2
997+
Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT NULL::bigint
998+
Optimizer: Postgres-based planner
999+
Settings: gp_enable_minmax_optimization = 'off'
1000+
(10 rows)
1001+
1002+
EXPLAIN (VERBOSE, COSTS OFF)
1003+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit all offset 998;
1004+
QUERY PLAN
1005+
------------------------------------------------------------------------------------------------------------
1006+
Limit
1007+
Output: c1, c2
1008+
-> Gather Motion 2:1 (slice1; segments: 2)
1009+
Output: c1, c2
1010+
Merge Key: c1
1011+
-> Foreign Scan on public.mpp_ft2
1012+
Output: c1, c2
1013+
Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT NULL::bigint
1014+
Optimizer: Postgres-based planner
1015+
Settings: gp_enable_minmax_optimization = 'off'
1016+
(10 rows)
1017+
1018+
EXPLAIN (VERBOSE, COSTS OFF)
1019+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 0 offset 998;
1020+
QUERY PLAN
1021+
-------------------------------------------------------------------------------------------------------------------------
1022+
Limit
1023+
Output: c1, c2
1024+
-> Gather Motion 2:1 (slice1; segments: 2)
1025+
Output: c1, c2
1026+
Merge Key: c1
1027+
-> Foreign Scan on public.mpp_ft2
1028+
Output: c1, c2
1029+
Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT 0::bigint
1030+
Optimizer: Postgres-based planner
1031+
Settings: gp_enable_minmax_optimization = 'off'
1032+
(10 rows)
1033+
1034+
EXPLAIN (VERBOSE, COSTS OFF)
1035+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 0 offset null;
1036+
QUERY PLAN
1037+
--------------------------------------------------------------------------------------------------------------------------
1038+
Limit
1039+
Output: c1, c2
1040+
-> Gather Motion 2:1 (slice1; segments: 2)
1041+
Output: c1, c2
1042+
Merge Key: c1
1043+
-> Foreign Scan on public.mpp_ft2
1044+
Output: c1, c2
1045+
Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT 0::bigint
1046+
Optimizer: Postgres-based planner
1047+
Settings: gp_enable_minmax_optimization = 'off'
1048+
(10 rows)
1049+
1050+
EXPLAIN (VERBOSE, COSTS OFF)
1051+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 3 offset null;
1052+
QUERY PLAN
1053+
--------------------------------------------------------------------------------------------------------------------------
1054+
Limit
1055+
Output: c1, c2
1056+
-> Gather Motion 2:1 (slice1; segments: 2)
1057+
Output: c1, c2
1058+
Merge Key: c1
1059+
-> Foreign Scan on public.mpp_ft2
1060+
Output: c1, c2
1061+
Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT 3::bigint
1062+
Optimizer: Postgres-based planner
1063+
Settings: gp_enable_minmax_optimization = 'off'
1064+
(10 rows)
1065+
1066+
EXPLAIN (VERBOSE, COSTS OFF)
1067+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 3 offset 0;
1068+
QUERY PLAN
1069+
-----------------------------------------------------------------------------------------------------------------------
1070+
Limit
1071+
Output: c1, c2
1072+
-> Gather Motion 2:1 (slice1; segments: 2)
1073+
Output: c1, c2
1074+
Merge Key: c1
1075+
-> Foreign Scan on public.mpp_ft2
1076+
Output: c1, c2
1077+
Remote SQL: SELECT c1, c2 FROM "MPP_S 1"."T 2" ORDER BY c1 ASC NULLS LAST LIMIT 3::bigint
1078+
Optimizer: Postgres-based planner
1079+
Settings: gp_enable_minmax_optimization = 'off'
1080+
(10 rows)
1081+
1082+
ALTER FOREIGN TABLE mpp_ft2 OPTIONS(set use_remote_estimate 'false');
9841083
-- Query with aggregates and limit clause together is NOT pushed down.
9851084
-- Because it's unsafe to do partial aggregate and limit in multiple remote servers.
9861085
EXPLAIN (VERBOSE, COSTS OFF)

contrib/postgres_fdw/sql/mpp_gp2pg_postgres_fdw.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,23 @@ SELECT c1, c2 FROM mpp_ft2 order by c1 offset 2 limit 3;
233233
EXPLAIN VERBOSE
234234
SELECT c1, c2 FROM mpp_ft2 order by c1 offset 998;
235235
SELECT c1, c2 FROM mpp_ft2 order by c1 offset 998;
236+
237+
-- test LIMIT 0, OFFSET null/0
238+
ALTER FOREIGN TABLE mpp_ft2 OPTIONS(set use_remote_estimate 'true');
239+
EXPLAIN (VERBOSE, COSTS OFF)
240+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit null offset 998;
241+
EXPLAIN (VERBOSE, COSTS OFF)
242+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit all offset 998;
243+
EXPLAIN (VERBOSE, COSTS OFF)
244+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 0 offset 998;
245+
EXPLAIN (VERBOSE, COSTS OFF)
246+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 0 offset null;
247+
EXPLAIN (VERBOSE, COSTS OFF)
248+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 3 offset null;
249+
EXPLAIN (VERBOSE, COSTS OFF)
250+
SELECT c1, c2 FROM mpp_ft2 order by c1 limit 3 offset 0;
251+
ALTER FOREIGN TABLE mpp_ft2 OPTIONS(set use_remote_estimate 'false');
252+
236253
-- Query with aggregates and limit clause together is NOT pushed down.
237254
-- Because it's unsafe to do partial aggregate and limit in multiple remote servers.
238255
EXPLAIN (VERBOSE, COSTS OFF)

0 commit comments

Comments
 (0)