aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-03-14 15:10:41 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2013-03-14 15:11:05 -0400
commit1a1832eb085e5bca198735e5d0e766a3cb61b8fc (patch)
tree1e465e6c0906223065db86966c8fe4640312950d /src
parentfb60e7296c2cf15195802b4596496b179bdc905a (diff)
downloadpostgresql-1a1832eb085e5bca198735e5d0e766a3cb61b8fc.tar.gz
postgresql-1a1832eb085e5bca198735e5d0e766a3cb61b8fc.zip
Avoid inserting no-op Limit plan nodes.
This was discussed in connection with the patch to avoid inserting no-op Result nodes, but not actually implemented therein.
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/plan/planner.c57
-rw-r--r--src/test/regress/expected/updatable_views.out60
2 files changed, 84 insertions, 33 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 670776b032b..db91b8277d9 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -68,6 +68,7 @@ static void preprocess_rowmarks(PlannerInfo *root);
static double preprocess_limit(PlannerInfo *root,
double tuple_fraction,
int64 *offset_est, int64 *count_est);
+static bool limit_needed(Query *parse);
static void preprocess_groupclause(PlannerInfo *root);
static bool choose_hashed_grouping(PlannerInfo *root,
double tuple_fraction, double limit_tuples,
@@ -1825,7 +1826,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
/*
* Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node.
*/
- if (parse->limitCount || parse->limitOffset)
+ if (limit_needed(parse))
{
result_plan = (Plan *) make_limit(result_plan,
parse->limitOffset,
@@ -2296,6 +2297,60 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
return tuple_fraction;
}
+/*
+ * limit_needed - do we actually need a Limit plan node?
+ *
+ * If we have constant-zero OFFSET and constant-null LIMIT, we can skip adding
+ * a Limit node. This is worth checking for because "OFFSET 0" is a common
+ * locution for an optimization fence. (Because other places in the planner
+ * merely check whether parse->limitOffset isn't NULL, it will still work as
+ * an optimization fence --- we're just suppressing unnecessary run-time
+ * overhead.)
+ *
+ * This might look like it could be merged into preprocess_limit, but there's
+ * a key distinction: here we need hard constants in OFFSET/LIMIT, whereas
+ * in preprocess_limit it's good enough to consider estimated values.
+ */
+static bool
+limit_needed(Query *parse)
+{
+ Node *node;
+
+ node = parse->limitCount;
+ if (node)
+ {
+ if (IsA(node, Const))
+ {
+ /* NULL indicates LIMIT ALL, ie, no limit */
+ if (!((Const *) node)->constisnull)
+ return true; /* LIMIT with a constant value */
+ }
+ else
+ return true; /* non-constant LIMIT */
+ }
+
+ node = parse->limitOffset;
+ if (node)
+ {
+ if (IsA(node, Const))
+ {
+ /* Treat NULL as no offset; the executor would too */
+ if (!((Const *) node)->constisnull)
+ {
+ int64 offset = DatumGetInt64(((Const *) node)->constvalue);
+
+ /* Executor would treat less-than-zero same as zero */
+ if (offset > 0)
+ return true; /* OFFSET with a positive value */
+ }
+ }
+ else
+ return true; /* non-constant OFFSET */
+ }
+
+ return false; /* don't need a Limit plan node */
+}
+
/*
* preprocess_groupclause - do preparatory work on GROUP BY clause
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index ead08d69b10..005bb0961e8 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -542,36 +542,34 @@ SELECT * FROM rw_view2;
(2 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------------
Update on base_tbl
-> Nested Loop
-> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (a = 2)
-> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
- -> Limit
- -> Bitmap Heap Scan on base_tbl base_tbl_1
- Recheck Cond: (a > 0)
- -> Bitmap Index Scan on base_tbl_pkey
- Index Cond: (a > 0)
-(11 rows)
+ -> Bitmap Heap Scan on base_tbl base_tbl_1
+ Recheck Cond: (a > 0)
+ -> Bitmap Index Scan on base_tbl_pkey
+ Index Cond: (a > 0)
+(10 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
- QUERY PLAN
-------------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------------
Delete on base_tbl
-> Nested Loop
-> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (a = 2)
-> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
- -> Limit
- -> Bitmap Heap Scan on base_tbl base_tbl_1
- Recheck Cond: (a > 0)
- -> Bitmap Index Scan on base_tbl_pkey
- Index Cond: (a > 0)
-(11 rows)
+ -> Bitmap Heap Scan on base_tbl base_tbl_1
+ Recheck Cond: (a > 0)
+ -> Bitmap Index Scan on base_tbl_pkey
+ Index Cond: (a > 0)
+(10 rows)
DROP TABLE base_tbl CASCADE;
NOTICE: drop cascades to 2 other objects
@@ -775,30 +773,28 @@ SELECT * FROM rw_view2;
(2 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
- QUERY PLAN
-------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------
Update on rw_view1 rw_view1_1
-> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
- -> Limit
- -> Bitmap Heap Scan on base_tbl
- Recheck Cond: (a > 0)
- -> Bitmap Index Scan on base_tbl_pkey
- Index Cond: (a > 0)
-(8 rows)
+ -> Bitmap Heap Scan on base_tbl
+ Recheck Cond: (a > 0)
+ -> Bitmap Index Scan on base_tbl_pkey
+ Index Cond: (a > 0)
+(7 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
- QUERY PLAN
-------------------------------------------------------------
+ QUERY PLAN
+----------------------------------------------------------
Delete on rw_view1 rw_view1_1
-> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
- -> Limit
- -> Bitmap Heap Scan on base_tbl
- Recheck Cond: (a > 0)
- -> Bitmap Index Scan on base_tbl_pkey
- Index Cond: (a > 0)
-(8 rows)
+ -> Bitmap Heap Scan on base_tbl
+ Recheck Cond: (a > 0)
+ -> Bitmap Index Scan on base_tbl_pkey
+ Index Cond: (a > 0)
+(7 rows)
DROP TABLE base_tbl CASCADE;
NOTICE: drop cascades to 2 other objects