SQL optimization

Offering: openGaussDev

More detail: support null_test short circuit

# Conflicts:
#	src/test/regress/parallel_schedule0

Match-id-b136e3ec8a8b1f7983c92aa6c68b395a2ea6bbd7
This commit is contained in:
openGaussDev 2022-03-04 16:44:45 +08:00 committed by yanghao
parent ab3ee6a00a
commit 3bb32d1d4a
4 changed files with 175 additions and 2 deletions

View File

@ -222,6 +222,8 @@ static bool relIsDeltaNode(PlannerInfo* root, RelOptInfo* relOptInfo);
static void ModifyWorktableWtParam(Node* planNode, int oldWtParam, int newWtParam);
static bool ScanQualsViolateNotNullConstr(PlannerInfo* root, RelOptInfo* rel, Path* best_path);
#define SATISFY_INFORMATIONAL_CONSTRAINT(joinPlan, joinType) \
(u_sess->attr.attr_sql.enable_constraint_optimization && true == innerPlan((joinPlan))->hasUniqueResults && \
JOIN_SEMI != (joinType) && JOIN_ANTI != (joinType))
@ -752,11 +754,49 @@ static Plan* create_scan_plan(PlannerInfo* root, Path* best_path)
*/
if (root->hasPseudoConstantQuals) {
plan = create_gating_plan(root, plan, scan_clauses);
} else if (ScanQualsViolateNotNullConstr(root, rel, best_path)) {
/*
* If there is IS NULL qual on a known NOT-NULL attribute, insert a Result node to prevent needless execution.
*/
plan = (Plan*)make_result(root, plan->targetlist, (Node*)list_make1(makeBoolConst(false, false)), plan);
}
return plan;
}
static bool IsScanPath(NodeTag type)
{
return (
type == T_CStoreScan || type == T_CStoreIndexScan || type == T_CStoreIndexHeapScan || type == T_SeqScan ||
type == T_DfsScan || type == T_IndexScan || type == T_IndexOnlyScan || type == T_BitmapHeapScan
);
}
static bool ScanQualsViolateNotNullConstr(PlannerInfo* root, RelOptInfo* rel, Path* best_path)
{
/* For now, we only support table scan optimization */
if (rel->rtekind != RTE_RELATION || !IsScanPath(best_path->pathtype)) {
return false;
}
List* scan_clauses = rel->baserestrictinfo;
ListCell* lc = NULL;
foreach (lc, scan_clauses) {
Node* clause = (Node*)lfirst(lc);
if (IsA(clause, RestrictInfo) && IsA(((RestrictInfo*)clause)->clause, NullTest)) {
NullTest* expr = (NullTest*)((RestrictInfo*)clause)->clause;
/* For attribute with NOT-NULL constraint, IS-NULL expression can be short-circuited */
if (expr->nulltesttype != IS_NULL || !IsA(expr->arg, Var)) {
continue;
}
if (check_var_nonnullable(root->parse, (Node*)expr->arg)) {
return true;
}
}
}
return false;
}
/*
* Build a target list (ie, a list of TargetEntry) for a relation.
*/

View File

@ -0,0 +1,100 @@
create schema null_test_opt_nsp;
set search_path = null_test_opt_nsp;
create table t(a int, b int not null);
insert into t values(1, 1);
explain (costs off) select * from t where b is null order by 1, 2;
QUERY PLAN
-----------------------------------
Sort
Sort Key: a, b
-> Result
One-Time Filter: false
-> Seq Scan on t
Filter: (b IS NULL)
(6 rows)
select * from t where b is null order by 1, 2;
a | b
---+---
(0 rows)
explain (costs off) select * from t where b is not null order by 1, 2;
QUERY PLAN
---------------------
Sort
Sort Key: a, b
-> Seq Scan on t
(3 rows)
select * from t where b is not null order by 1, 2;
a | b
---+---
1 | 1
(1 row)
explain (costs off) select * from t where b is null or b is not null order by 1, 2;
QUERY PLAN
---------------------
Sort
Sort Key: a, b
-> Seq Scan on t
(3 rows)
select * from t where b is null or b is not null order by 1, 2;
a | b
---+---
1 | 1
(1 row)
explain (costs off) select * from t where b is null or a = 1 order by 1, 2;
QUERY PLAN
------------------------------------------
Sort
Sort Key: a, b
-> Seq Scan on t
Filter: ((b IS NULL) OR (a = 1))
(4 rows)
select * from t where b is null or a = 1 order by 1, 2;
a | b
---+---
1 | 1
(1 row)
explain (costs off) select * from t where b is null and a = 1 order by 1, 2;
QUERY PLAN
-------------------------------------------------
Sort
Sort Key: b
-> Result
One-Time Filter: false
-> Seq Scan on t
Filter: ((b IS NULL) AND (a = 1))
(6 rows)
select * from t where b is null and a = 1 order by 1, 2;
a | b
---+---
(0 rows)
explain (costs off) select * from t tt1 join t tt2 on tt1.a = tt2.b where tt1.a is null;
QUERY PLAN
-----------------------------------------
Hash Join
Hash Cond: (tt1.a = tt2.b)
-> Seq Scan on t tt1
Filter: (a IS NULL)
-> Hash
-> Result
One-Time Filter: false
-> Seq Scan on t tt2
Filter: (b IS NULL)
(9 rows)
select * from t tt1 join t tt2 on tt1.a = tt2.b where tt1.a is null;
a | b | a | b
---+---+---+---
(0 rows)
drop schema null_test_opt_nsp cascade;
NOTICE: drop cascades to table t

View File

@ -25,8 +25,8 @@ test: pldeveloper_gs_source
test: index_advisor
test: pl_debugger_server pl_debugger_client
test: update_for_wait_s1 update_for_wait_s2
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud
test: large_sequence int16 gs_dump_sequence
test: plan_hint plan_hint_set plan_hint_no_expand plan_hint_iud null_test_opt
test: large_sequence int16 forall_save_exceptions gs_dump_sequence
test: gs_dump_tableof
test: analyze_commands
#test: single_node_job

View File

@ -0,0 +1,33 @@
create schema null_test_opt_nsp;
set search_path = null_test_opt_nsp;
create table t(a int, b int not null);
insert into t values(1, 1);
explain (costs off) select * from t where b is null order by 1, 2;
select * from t where b is null order by 1, 2;
explain (costs off) select * from t where b is not null order by 1, 2;
select * from t where b is not null order by 1, 2;
explain (costs off) select * from t where b is null or b is not null order by 1, 2;
select * from t where b is null or b is not null order by 1, 2;
explain (costs off) select * from t where b is null or a = 1 order by 1, 2;
select * from t where b is null or a = 1 order by 1, 2;
explain (costs off) select * from t where b is null and a = 1 order by 1, 2;
select * from t where b is null and a = 1 order by 1, 2;
explain (costs off) select * from t tt1 join t tt2 on tt1.a = tt2.b where tt1.a is null;
select * from t tt1 join t tt2 on tt1.a = tt2.b where tt1.a is null;
drop schema null_test_opt_nsp cascade;