submit code to openGauss-server
Offering: openGaussDev More detail:range分区表PBE单分区剪枝 Signed-off-by:lihaixiao lihaixiao3@huawei.com Match-id-a88ff128079ca680f33a7419eeab078bacf466d6
This commit is contained in:
@ -678,6 +678,9 @@ static void _outPruningResult(StringInfo str, PruningResult* node)
|
||||
if (t_thrd.proc->workingVersionNum >= num) {
|
||||
WRITE_NODE_FIELD(expr);
|
||||
}
|
||||
if (t_thrd.proc->workingVersionNum >= PBESINGLEPARTITION_VERSION_NUM) {
|
||||
WRITE_BOOL_FIELD(isPbeSinlePartition);
|
||||
}
|
||||
}
|
||||
|
||||
static void _outSubPartitionPruningResult(StringInfo str, SubPartitionPruningResult* node)
|
||||
|
||||
@ -3312,6 +3312,9 @@ static PruningResult* _readPruningResult(PruningResult* local_node)
|
||||
if (t_thrd.proc->workingVersionNum >= num) {
|
||||
READ_NODE_FIELD(expr);
|
||||
}
|
||||
IF_EXIST(isPbeSinlePartition) {
|
||||
READ_BOOL_FIELD(isPbeSinlePartition);
|
||||
}
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
@ -65,6 +65,7 @@ const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
||||
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||
const uint32 FUNC_PARAM_COL_VERSION_NUM = 92500;
|
||||
const uint32 SUBPARTITION_VERSION_NUM = 92436;
|
||||
const uint32 PBESINGLEPARTITION_VERSION_NUM = 92523;
|
||||
const uint32 DEFAULT_MAT_CTE_NUM = 92429;
|
||||
const uint32 MATERIALIZED_CTE_NUM = 92424;
|
||||
const uint32 HINT_ENHANCEMENT_VERSION_NUM = 92359;
|
||||
|
||||
@ -873,6 +873,31 @@ static void SetPlainReSizeWithPruningRatio(RelOptInfo *rel, double pruningRatio)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function applies only to single partition key of range partitioned tables in PBE mode.
|
||||
*/
|
||||
static bool IsPbeSinglePartition(Relation rel, RelOptInfo* relInfo)
|
||||
{
|
||||
if (relInfo->pruning_result->paramArg == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (RelationIsSubPartitioned(rel)) {
|
||||
return false;
|
||||
}
|
||||
if (rel->partMap->type != PART_TYPE_RANGE) {
|
||||
return false;
|
||||
}
|
||||
RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap;
|
||||
int partKeyNum = partMap->partitionKey->dim1;
|
||||
if (partKeyNum > 1) {
|
||||
return false;
|
||||
}
|
||||
if (relInfo->pruning_result->isPbeSinlePartition) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* set_plain_rel_size
|
||||
* Set size estimates for a plain relation (no subquery, no inheritance)
|
||||
@ -896,8 +921,7 @@ static void set_plain_rel_size(PlannerInfo* root, RelOptInfo* rel, RangeTblEntry
|
||||
|
||||
Assert(rel->pruning_result);
|
||||
|
||||
|
||||
if (rel->pruning_result->expr != NULL) {
|
||||
if (IsPbeSinglePartition(relation, rel)) {
|
||||
rel->partItrs = 1;
|
||||
} else {
|
||||
/* set flag for dealing with partintioned table */
|
||||
|
||||
@ -460,17 +460,21 @@ PruningResult* partitionPruningForExpr(PlannerInfo* root, RangeTblEntry* rte, Re
|
||||
context->pruningType = PruningPartition;
|
||||
|
||||
if (rel->partMap != NULL && (rel->partMap->type == PART_TYPE_LIST || rel->partMap->type == PART_TYPE_HASH)) {
|
||||
// for List/Hash partitioned table
|
||||
result = partitionEqualPruningWalker(rel->partMap->type, expr, context);
|
||||
} else {
|
||||
// for Range/Interval partitioned table
|
||||
result = partitionPruningWalker(expr, context);
|
||||
}
|
||||
|
||||
if (result->exprPart != NULL || result->paramArg != NULL) {
|
||||
Param* paramArg = (Param *)copyObject(result->paramArg);
|
||||
bool isPbeSinlePartition = result->isPbeSinlePartition;
|
||||
destroyPruningResult(result);
|
||||
result = getFullPruningResult(rel);
|
||||
result->expr = expr;
|
||||
result->paramArg = paramArg;
|
||||
result->isPbeSinlePartition = isPbeSinlePartition;
|
||||
return result;
|
||||
}
|
||||
/* Never happen, just to be self-contained */
|
||||
@ -535,10 +539,12 @@ PruningResult* partitionPruningWalker(Expr* expr, PruningContext* pruningCtx)
|
||||
result = makeNode(PruningResult);
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
}
|
||||
result->isPbeSinlePartition = false;
|
||||
} break;
|
||||
default: {
|
||||
result = makeNode(PruningResult);
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
} break;
|
||||
}
|
||||
|
||||
@ -619,6 +625,7 @@ static PruningResult* partitionPruningFromBoolExpr(const BoolExpr* expr, Pruning
|
||||
if (expr->boolop == NOT_EXPR) {
|
||||
result = makeNode(PruningResult);
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -638,6 +645,7 @@ static PruningResult* partitionPruningFromBoolExpr(const BoolExpr* expr, Pruning
|
||||
break;
|
||||
case OR_EXPR:
|
||||
result = unionChildPruningResult(resultList, context);
|
||||
result->isPbeSinlePartition = false;
|
||||
break;
|
||||
case NOT_EXPR:
|
||||
default:
|
||||
@ -750,6 +758,7 @@ static PruningResult* partitionPruningFromNullTest(NullTest* expr, PruningContex
|
||||
}
|
||||
|
||||
result->state = PRUNING_RESULT_SUBSET;
|
||||
result->isPbeSinlePartition = true;
|
||||
|
||||
result->bm_rangeSelectedPartitions = bms_make_singleton(partMap->rangeElementsNum - 1);
|
||||
|
||||
@ -832,6 +841,7 @@ static PruningResult* intersectChildPruningResult(const List* resultList, Prunin
|
||||
AssertEreport(iteratorResult, MOD_OPT, "iteratorResult context is NNULL.");
|
||||
if (iteratorResult->state == PRUNING_RESULT_EMPTY) {
|
||||
result->state = PRUNING_RESULT_EMPTY;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
} else if (iteratorResult->state == PRUNING_RESULT_FULL) {
|
||||
continue;
|
||||
@ -875,17 +885,22 @@ static PruningResult* intersectChildPruningResult(const List* resultList, Prunin
|
||||
|
||||
if (BoundaryIsEmpty(result->boundary)) {
|
||||
result->state = PRUNING_RESULT_EMPTY;
|
||||
result->isPbeSinlePartition = false;
|
||||
break;
|
||||
}
|
||||
|
||||
result->state = PRUNING_RESULT_SUBSET;
|
||||
}
|
||||
if (result->state != PRUNING_RESULT_EMPTY && iteratorResult->isPbeSinlePartition) {
|
||||
result->isPbeSinlePartition = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (PruningResultIsEmpty(result)) {
|
||||
destroyPruningResult(result);
|
||||
result = makeNode(PruningResult);
|
||||
result->state = PRUNING_RESULT_EMPTY;
|
||||
result->isPbeSinlePartition = false;
|
||||
result->intervalOffset = -1;
|
||||
}
|
||||
|
||||
@ -981,6 +996,7 @@ static PruningResult* partitionPruningFromScalarArrayOpExpr
|
||||
if (T_Var != nodeTag(larg) || (T_ArrayExpr != nodeTag(rarg) && T_Const != nodeTag(rarg))) {
|
||||
result = makeNode(PruningResult);
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1079,6 +1095,7 @@ static PruningResult* partitionPruningFromScalarArrayOpExpr
|
||||
} else {
|
||||
result = makeNode(PruningResult);
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1258,6 +1275,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
/* length of args MUST be 2 */
|
||||
if (!PointerIsValid(expr) || list_length(expr->args) != 2 || !PointerIsValid(opName = get_opname(expr->opno))) {
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1296,6 +1314,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
((T_Const == nodeTag(rightArg) || T_Param == nodeTag(rightArg)
|
||||
|| T_OpExpr == nodeTag(rightArg)) && T_Var == nodeTag(leftArg)))) {
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1325,6 +1344,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
if (context->rte != NULL &&
|
||||
context->rte->relid != context->relation->rd_id) {
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
@ -1334,6 +1354,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
paramArg != NULL ||
|
||||
exprPart != NULL) {
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1351,25 +1372,32 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
if (exprPart != NULL) {
|
||||
if (!PartitionMapIsRange(partMap)) {
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
} else {
|
||||
result->exprPart = exprPart;
|
||||
result->state = PRUNING_RESULT_SUBSET;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
} else if (paramArg != NULL) {
|
||||
if (paramArg->paramkind != PARAM_EXTERN || !PartitionMapIsRange(partMap)) {
|
||||
result->state = PRUNING_RESULT_FULL;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
} else {
|
||||
result->paramArg = paramArg;
|
||||
result->state = PRUNING_RESULT_SUBSET;
|
||||
if (0 == strcmp("=", opName)) {
|
||||
result->isPbeSinlePartition = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (constArg->constisnull) {
|
||||
result->state = PRUNING_RESULT_EMPTY;
|
||||
result->isPbeSinlePartition = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1377,6 +1405,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
result->boundary = makePruningBoundary(partKeyNum);
|
||||
|
||||
boundary = result->boundary;
|
||||
result->isPbeSinlePartition = false;
|
||||
|
||||
/* decide the const is the top or bottom of boundary */
|
||||
if ((0 == strcmp(">", opName) && rightArgIsConst) || (0 == strcmp("<", opName) && !rightArgIsConst)) {
|
||||
@ -1409,6 +1438,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex
|
||||
|
||||
boundary->state = PRUNING_RESULT_SUBSET;
|
||||
result->state = PRUNING_RESULT_SUBSET;
|
||||
result->isPbeSinlePartition = true;
|
||||
} else if ((0 == strcmp("<=", opName) && rightArgIsConst) || (0 == strcmp(">=", opName) && !rightArgIsConst)) {
|
||||
boundary->maxClose[attrOffset] = true;
|
||||
boundary->max[attrOffset] = PointerGetDatum(constArg);
|
||||
|
||||
@ -768,7 +768,11 @@ static void ExecInitPartitionForTidScan(TidScanState* tidstate, EState* estate)
|
||||
lock = (relistarget ? RowExclusiveLock : AccessShareLock);
|
||||
tidstate->ss.lockMode = lock;
|
||||
|
||||
Assert(plan->scan.itrs == plan->scan.pruningInfo->ls_rangeSelectedPartitions->length);
|
||||
if (plan->scan.pruningInfo->ls_rangeSelectedPartitions != NULL) {
|
||||
plan->scan.itrs = plan->scan.pruningInfo->ls_rangeSelectedPartitions->length;
|
||||
} else {
|
||||
plan->scan.itrs = 0;
|
||||
}
|
||||
|
||||
foreach (cell, part_seqs) {
|
||||
Oid table_partitionid = InvalidOid;
|
||||
|
||||
@ -44,6 +44,7 @@ extern const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM;
|
||||
extern const uint32 UPSERT_WHERE_VERSION_NUM;
|
||||
extern const uint32 FUNC_PARAM_COL_VERSION_NUM;
|
||||
extern const uint32 SUBPARTITION_VERSION_NUM;
|
||||
extern const uint32 PBESINGLEPARTITION_VERSION_NUM;
|
||||
extern const uint32 COMMENT_PROC_VERSION_NUM;
|
||||
extern const uint32 COMMENT_ROWTYPE_TABLEOF_VERSION_NUM;
|
||||
extern const uint32 COMMENT_PCT_TYPE_VERSION_NUM;
|
||||
|
||||
@ -470,6 +470,8 @@ typedef struct PruningResult {
|
||||
Param* paramArg;
|
||||
OpExpr* exprPart;
|
||||
Expr* expr;
|
||||
/* This variable applies only to single-partition key range partition tables in PBE mode. */
|
||||
bool isPbeSinlePartition = false;
|
||||
} PruningResult;
|
||||
|
||||
extern Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID);
|
||||
|
||||
@ -2641,5 +2641,95 @@ delete from test_bypass_sql_partition where col1 <= 11 and col1 >= 15;
|
||||
delete from test_bypass_sql_partition where col1 > 10;
|
||||
delete from test_bypass_sql_partition where col1 < 10;
|
||||
delete from test_bypass_sql_partition where col1 >= 10 and col1 <= 30;
|
||||
create table t1(
|
||||
crcrd_acg_setl_dt char(8) not null,
|
||||
cst_id char(18),
|
||||
multi_tenancy_id char(5)
|
||||
)
|
||||
partition by range (multi_tenancy_id, crcrd_acg_setl_dt)
|
||||
(
|
||||
partition p1 values less than ('CN000', '20191201'),
|
||||
partition p2 values less than ('CN000', '20200201'),
|
||||
partition p3 values less than ('CN000', '20200202'),
|
||||
partition p4 values less than ('CN000', '20200203'),
|
||||
partition p5 values less than ('CN000', '20200204'),
|
||||
partition p6 values less than ('ZZZZZ', '21000101')
|
||||
)
|
||||
enable row movement
|
||||
;
|
||||
|
||||
create index on t1(crcrd_acg_setl_dt, cst_id, multi_tenancy_id) local;
|
||||
|
||||
insert into t1 values('20200201', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200225', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200228', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200301', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200310', '107190000103394943', 'CN000');
|
||||
|
||||
set enable_seqscan = off;
|
||||
|
||||
select max(crcrd_acg_setl_dt) from t1 where cst_id='107190000103394943' and multi_tenancy_id = 'CN000';
|
||||
max
|
||||
----------
|
||||
20200310
|
||||
(1 row)
|
||||
|
||||
|
||||
prepare p1 as select max(crcrd_acg_setl_dt) from t1 where cst_id=$1 and multi_tenancy_id = $2;
|
||||
|
||||
execute p1 ('107190000103394943','CN000');
|
||||
max
|
||||
----------
|
||||
20200310
|
||||
(1 row)
|
||||
|
||||
deallocate p1;
|
||||
drop table t1;
|
||||
drop table test_range_pt;
|
||||
ERROR: table "test_range_pt" does not exist
|
||||
create table test_range_pt (a int, b int, c int)
|
||||
partition by range(a)
|
||||
(
|
||||
partition p1 values less than (2000),
|
||||
partition p2 values less than (3000),
|
||||
partition p3 values less than (4000),
|
||||
partition p4 values less than (5000),
|
||||
partition p5 values less than (maxvalue)
|
||||
)ENABLE ROW MOVEMENT;
|
||||
insert into test_range_pt values(1,1),(2001,2),(3001,3),(4001,4),(5001,5);
|
||||
|
||||
create index idx1 on test_range_pt(a) local;
|
||||
prepare p1 as select max(a) from test_range_pt where a>$1;
|
||||
execute p1 (1);
|
||||
max
|
||||
------
|
||||
5001
|
||||
(1 row)
|
||||
|
||||
deallocate p1;
|
||||
select max(a) from test_range_pt where a>b+1;
|
||||
max
|
||||
------
|
||||
5001
|
||||
(1 row)
|
||||
|
||||
drop table test_range_pt;
|
||||
drop table test_list_lt1;
|
||||
ERROR: table "test_list_lt1" does not exist
|
||||
create table test_list_lt1 (a int, b int )
|
||||
partition by list(a)
|
||||
(
|
||||
partition p1 values (2000),
|
||||
partition p2 values (3000),
|
||||
partition p3 values (4000)
|
||||
) ;
|
||||
prepare p1 as select * from test_list_lt1 where a = $1 and ctid = '(0,1)';
|
||||
execute p1 (1);
|
||||
a | b
|
||||
---+---
|
||||
(0 rows)
|
||||
|
||||
deallocate p1;
|
||||
drop table test_list_lt1;
|
||||
reset enable_partition_opfusion;
|
||||
drop table test_bypass_sql_partition;
|
||||
|
||||
@ -250,6 +250,73 @@ delete from test_bypass_sql_partition where col1 <= 11 and col1 >= 15;
|
||||
delete from test_bypass_sql_partition where col1 > 10;
|
||||
delete from test_bypass_sql_partition where col1 < 10;
|
||||
delete from test_bypass_sql_partition where col1 >= 10 and col1 <= 30;
|
||||
|
||||
create table t1(
|
||||
crcrd_acg_setl_dt char(8) not null,
|
||||
cst_id char(18),
|
||||
multi_tenancy_id char(5)
|
||||
)
|
||||
partition by range (multi_tenancy_id, crcrd_acg_setl_dt)
|
||||
(
|
||||
partition p1 values less than ('CN000', '20191201'),
|
||||
partition p2 values less than ('CN000', '20200201'),
|
||||
partition p3 values less than ('CN000', '20200202'),
|
||||
partition p4 values less than ('CN000', '20200203'),
|
||||
partition p5 values less than ('CN000', '20200204'),
|
||||
partition p6 values less than ('ZZZZZ', '21000101')
|
||||
)
|
||||
enable row movement
|
||||
;
|
||||
|
||||
create index on t1(crcrd_acg_setl_dt, cst_id, multi_tenancy_id) local;
|
||||
|
||||
insert into t1 values('20200201', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200225', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200228', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200301', '107190000103394943', 'CN000');
|
||||
insert into t1 values('20200310', '107190000103394943', 'CN000');
|
||||
|
||||
set enable_seqscan = off;
|
||||
|
||||
select max(crcrd_acg_setl_dt) from t1 where cst_id='107190000103394943' and multi_tenancy_id = 'CN000';
|
||||
|
||||
prepare p1 as select max(crcrd_acg_setl_dt) from t1 where cst_id=$1 and multi_tenancy_id = $2;
|
||||
|
||||
execute p1 ('107190000103394943','CN000');
|
||||
deallocate p1;
|
||||
|
||||
drop table t1;
|
||||
drop table test_range_pt;
|
||||
create table test_range_pt (a int, b int, c int)
|
||||
partition by range(a)
|
||||
(
|
||||
partition p1 values less than (2000),
|
||||
partition p2 values less than (3000),
|
||||
partition p3 values less than (4000),
|
||||
partition p4 values less than (5000),
|
||||
partition p5 values less than (maxvalue)
|
||||
)ENABLE ROW MOVEMENT;
|
||||
insert into test_range_pt values(1,1),(2001,2),(3001,3),(4001,4),(5001,5);
|
||||
|
||||
create index idx1 on test_range_pt(a) local;
|
||||
prepare p1 as select max(a) from test_range_pt where a>$1;
|
||||
execute p1 (1);
|
||||
deallocate p1;
|
||||
select max(a) from test_range_pt where a>b+1;
|
||||
drop table test_range_pt;
|
||||
drop table test_list_lt1;
|
||||
create table test_list_lt1 (a int, b int )
|
||||
partition by list(a)
|
||||
(
|
||||
partition p1 values (2000),
|
||||
partition p2 values (3000),
|
||||
partition p3 values (4000)
|
||||
) ;
|
||||
prepare p1 as select * from test_list_lt1 where a = $1 and ctid = '(0,1)';
|
||||
execute p1 (1);
|
||||
deallocate p1;
|
||||
drop table test_list_lt1;
|
||||
|
||||
reset enable_partition_opfusion;
|
||||
drop table test_bypass_sql_partition;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user