提交 1a1832eb 编写于 作者: T Tom Lane

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.
上级 fb60e729
...@@ -68,6 +68,7 @@ static void preprocess_rowmarks(PlannerInfo *root); ...@@ -68,6 +68,7 @@ static void preprocess_rowmarks(PlannerInfo *root);
static double preprocess_limit(PlannerInfo *root, static double preprocess_limit(PlannerInfo *root,
double tuple_fraction, double tuple_fraction,
int64 *offset_est, int64 *count_est); int64 *offset_est, int64 *count_est);
static bool limit_needed(Query *parse);
static void preprocess_groupclause(PlannerInfo *root); static void preprocess_groupclause(PlannerInfo *root);
static bool choose_hashed_grouping(PlannerInfo *root, static bool choose_hashed_grouping(PlannerInfo *root,
double tuple_fraction, double limit_tuples, double tuple_fraction, double limit_tuples,
...@@ -1825,7 +1826,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) ...@@ -1825,7 +1826,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
/* /*
* Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node. * 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, result_plan = (Plan *) make_limit(result_plan,
parse->limitOffset, parse->limitOffset,
...@@ -2296,6 +2297,60 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction, ...@@ -2296,6 +2297,60 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
return 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 * preprocess_groupclause - do preparatory work on GROUP BY clause
......
...@@ -542,36 +542,34 @@ SELECT * FROM rw_view2; ...@@ -542,36 +542,34 @@ SELECT * FROM rw_view2;
(2 rows) (2 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2; EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------ ----------------------------------------------------------------
Update on base_tbl Update on base_tbl
-> Nested Loop -> Nested Loop
-> Index Scan using base_tbl_pkey on base_tbl -> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (a = 2) Index Cond: (a = 2)
-> Subquery Scan on rw_view1 -> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
-> Limit -> Bitmap Heap Scan on base_tbl base_tbl_1
-> Bitmap Heap Scan on base_tbl base_tbl_1 Recheck Cond: (a > 0)
Recheck Cond: (a > 0) -> Bitmap Index Scan on base_tbl_pkey
-> Bitmap Index Scan on base_tbl_pkey Index Cond: (a > 0)
Index Cond: (a > 0) (10 rows)
(11 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2; EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------ ----------------------------------------------------------------
Delete on base_tbl Delete on base_tbl
-> Nested Loop -> Nested Loop
-> Index Scan using base_tbl_pkey on base_tbl -> Index Scan using base_tbl_pkey on base_tbl
Index Cond: (a = 2) Index Cond: (a = 2)
-> Subquery Scan on rw_view1 -> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
-> Limit -> Bitmap Heap Scan on base_tbl base_tbl_1
-> Bitmap Heap Scan on base_tbl base_tbl_1 Recheck Cond: (a > 0)
Recheck Cond: (a > 0) -> Bitmap Index Scan on base_tbl_pkey
-> Bitmap Index Scan on base_tbl_pkey Index Cond: (a > 0)
Index Cond: (a > 0) (10 rows)
(11 rows)
DROP TABLE base_tbl CASCADE; DROP TABLE base_tbl CASCADE;
NOTICE: drop cascades to 2 other objects NOTICE: drop cascades to 2 other objects
...@@ -775,30 +773,28 @@ SELECT * FROM rw_view2; ...@@ -775,30 +773,28 @@ SELECT * FROM rw_view2;
(2 rows) (2 rows)
EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2; EXPLAIN (costs off) UPDATE rw_view2 SET a=3 WHERE a=2;
QUERY PLAN QUERY PLAN
------------------------------------------------------------ ----------------------------------------------------------
Update on rw_view1 rw_view1_1 Update on rw_view1 rw_view1_1
-> Subquery Scan on rw_view1 -> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
-> Limit -> Bitmap Heap Scan on base_tbl
-> Bitmap Heap Scan on base_tbl Recheck Cond: (a > 0)
Recheck Cond: (a > 0) -> Bitmap Index Scan on base_tbl_pkey
-> Bitmap Index Scan on base_tbl_pkey Index Cond: (a > 0)
Index Cond: (a > 0) (7 rows)
(8 rows)
EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2; EXPLAIN (costs off) DELETE FROM rw_view2 WHERE a=2;
QUERY PLAN QUERY PLAN
------------------------------------------------------------ ----------------------------------------------------------
Delete on rw_view1 rw_view1_1 Delete on rw_view1 rw_view1_1
-> Subquery Scan on rw_view1 -> Subquery Scan on rw_view1
Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2)) Filter: ((rw_view1.a < 10) AND (rw_view1.a = 2))
-> Limit -> Bitmap Heap Scan on base_tbl
-> Bitmap Heap Scan on base_tbl Recheck Cond: (a > 0)
Recheck Cond: (a > 0) -> Bitmap Index Scan on base_tbl_pkey
-> Bitmap Index Scan on base_tbl_pkey Index Cond: (a > 0)
Index Cond: (a > 0) (7 rows)
(8 rows)
DROP TABLE base_tbl CASCADE; DROP TABLE base_tbl CASCADE;
NOTICE: drop cascades to 2 other objects NOTICE: drop cascades to 2 other objects
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册