mirror of https://github.com/citusdata/citus.git
Not use predicate_refuted_by when pruning chunks
parent
29641f9ef2
commit
3e14b8022e
|
@ -22,6 +22,7 @@
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/shard_pruning.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
|
@ -122,11 +123,9 @@ static ColumnBuffers * LoadColumnBuffers(Relation relation,
|
||||||
static bool * SelectedChunkMask(StripeSkipList *stripeSkipList,
|
static bool * SelectedChunkMask(StripeSkipList *stripeSkipList,
|
||||||
List *projectedColumnList, List *whereClauseList,
|
List *projectedColumnList, List *whereClauseList,
|
||||||
int64 *chunkGroupsFiltered);
|
int64 *chunkGroupsFiltered);
|
||||||
static List * BuildRestrictInfoList(List *whereClauseList);
|
static bool CanPruneChunk(List *pruningInstances,
|
||||||
static Node * BuildBaseConstraint(Var *variable);
|
ColumnChunkSkipNode *chunkSkipNode,
|
||||||
static OpExpr * MakeOpExpression(Var *variable, int16 strategyNumber);
|
FunctionCallInfo compareFunctionCall);
|
||||||
static Oid GetOperatorByType(Oid typeId, Oid accessMethodId, int16 strategyNumber);
|
|
||||||
static void UpdateConstraint(Node *baseConstraint, Datum minValue, Datum maxValue);
|
|
||||||
static StripeSkipList * SelectedChunkSkipList(StripeSkipList *stripeSkipList,
|
static StripeSkipList * SelectedChunkSkipList(StripeSkipList *stripeSkipList,
|
||||||
bool *projectedColumnMask,
|
bool *projectedColumnMask,
|
||||||
bool *selectedChunkMask);
|
bool *selectedChunkMask);
|
||||||
|
@ -708,7 +707,6 @@ SelectedChunkMask(StripeSkipList *stripeSkipList, List *projectedColumnList,
|
||||||
{
|
{
|
||||||
ListCell *columnCell = NULL;
|
ListCell *columnCell = NULL;
|
||||||
uint32 chunkIndex = 0;
|
uint32 chunkIndex = 0;
|
||||||
List *restrictInfoList = BuildRestrictInfoList(whereClauseList);
|
|
||||||
|
|
||||||
bool *selectedChunkMask = palloc0(stripeSkipList->chunkCount * sizeof(bool));
|
bool *selectedChunkMask = palloc0(stripeSkipList->chunkCount * sizeof(bool));
|
||||||
memset(selectedChunkMask, true, stripeSkipList->chunkCount * sizeof(bool));
|
memset(selectedChunkMask, true, stripeSkipList->chunkCount * sizeof(bool));
|
||||||
|
@ -727,30 +725,30 @@ SelectedChunkMask(StripeSkipList *stripeSkipList, List *projectedColumnList,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *baseConstraint = BuildBaseConstraint(column);
|
FunctionCall2InfoData comparisonFunctionCall2InfoData;
|
||||||
|
InitFunctionCallInfoData(*(FunctionCallInfo) & comparisonFunctionCall2InfoData,
|
||||||
|
comparisonFunction, 2, column->varcollid,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
List *pruningInstanceList =
|
||||||
|
BuildPruningInstanceList(column, whereClauseList,
|
||||||
|
&comparisonFunctionCall2InfoData);
|
||||||
|
if (list_length(pruningInstanceList) == 0)
|
||||||
|
{
|
||||||
|
/* CanPruneChunk already checks but do short-circuit here */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (chunkIndex = 0; chunkIndex < stripeSkipList->chunkCount; chunkIndex++)
|
for (chunkIndex = 0; chunkIndex < stripeSkipList->chunkCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
ColumnChunkSkipNode *chunkSkipNodeArray =
|
ColumnChunkSkipNode *chunkSkipNodeArray =
|
||||||
stripeSkipList->chunkSkipNodeArray[columnIndex];
|
stripeSkipList->chunkSkipNodeArray[columnIndex];
|
||||||
ColumnChunkSkipNode *chunkSkipNode = &chunkSkipNodeArray[chunkIndex];
|
ColumnChunkSkipNode *chunkSkipNode = &chunkSkipNodeArray[chunkIndex];
|
||||||
|
if (selectedChunkMask[chunkIndex] &&
|
||||||
/*
|
CanPruneChunk(pruningInstanceList, chunkSkipNode,
|
||||||
* A column chunk with comparable data type can miss min/max values
|
(FunctionCallInfo) & comparisonFunctionCall2InfoData))
|
||||||
* if all values in the chunk are NULL.
|
|
||||||
*/
|
|
||||||
if (!chunkSkipNode->hasMinMax)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateConstraint(baseConstraint, chunkSkipNode->minimumValue,
|
|
||||||
chunkSkipNode->maximumValue);
|
|
||||||
|
|
||||||
List *constraintList = list_make1(baseConstraint);
|
|
||||||
bool predicateRefuted =
|
|
||||||
predicate_refuted_by(constraintList, restrictInfoList, false);
|
|
||||||
if (predicateRefuted && selectedChunkMask[chunkIndex])
|
|
||||||
{
|
{
|
||||||
|
/* TODO: mark other chunks in the group too */
|
||||||
selectedChunkMask[chunkIndex] = false;
|
selectedChunkMask[chunkIndex] = false;
|
||||||
*chunkGroupsFiltered += 1;
|
*chunkGroupsFiltered += 1;
|
||||||
}
|
}
|
||||||
|
@ -761,6 +759,57 @@ SelectedChunkMask(StripeSkipList *stripeSkipList, List *projectedColumnList,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CanPruneChunk returns true if given list of prune instances prune given chunk.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
CanPruneChunk(List *pruningInstances, ColumnChunkSkipNode *chunkSkipNode,
|
||||||
|
FunctionCallInfo compareFunctionCall)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* A column chunk with comparable data type can miss min/max values
|
||||||
|
* if all values in the chunk are NULL.
|
||||||
|
*/
|
||||||
|
if (!chunkSkipNode->hasMinMax)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_length(pruningInstances) == 0)
|
||||||
|
{
|
||||||
|
/* we have no instances that can prune the chunk */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PruningInstance *pruneInstance = NULL;
|
||||||
|
foreach_ptr(pruneInstance, pruningInstances)
|
||||||
|
{
|
||||||
|
if (pruneInstance->isPartial)
|
||||||
|
{
|
||||||
|
/* skip partial instance since a fully built one has also been added */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pruneInstance->hasValidConstraint)
|
||||||
|
{
|
||||||
|
/* cannot prove that given instance wouldn't prune the chunk */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ExhaustivePruneOneWithMinMax(pruneInstance, compareFunctionCall,
|
||||||
|
chunkSkipNode->minimumValue,
|
||||||
|
chunkSkipNode->maximumValue))
|
||||||
|
{
|
||||||
|
/* found an instance that doesn't prune the chunk */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all OR'ed prune instances prune the given chunk */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetFunctionInfoOrNull first resolves the operator for the given data type,
|
* GetFunctionInfoOrNull first resolves the operator for the given data type,
|
||||||
* access method, and support procedure. The function then uses the resolved
|
* access method, and support procedure. The function then uses the resolved
|
||||||
|
@ -798,135 +847,6 @@ GetFunctionInfoOrNull(Oid typeId, Oid accessMethodId, int16 procedureId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* BuildRestrictInfoList builds restrict info list using the selection criteria,
|
|
||||||
* and then return this list. The function is copied from CitusDB's shard pruning
|
|
||||||
* logic.
|
|
||||||
*/
|
|
||||||
static List *
|
|
||||||
BuildRestrictInfoList(List *whereClauseList)
|
|
||||||
{
|
|
||||||
List *restrictInfoList = NIL;
|
|
||||||
|
|
||||||
ListCell *qualCell = NULL;
|
|
||||||
foreach(qualCell, whereClauseList)
|
|
||||||
{
|
|
||||||
Node *qualNode = (Node *) lfirst(qualCell);
|
|
||||||
|
|
||||||
RestrictInfo *restrictInfo = make_simple_restrictinfo((Expr *) qualNode);
|
|
||||||
restrictInfoList = lappend(restrictInfoList, restrictInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return restrictInfoList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* BuildBaseConstraint builds and returns a base constraint. This constraint
|
|
||||||
* implements an expression in the form of (var <= max && var >= min), where
|
|
||||||
* min and max values represent a chunk's min and max values. These chunk
|
|
||||||
* values are filled in after the constraint is built. This function is based
|
|
||||||
* on a similar function from CitusDB's shard pruning logic.
|
|
||||||
*/
|
|
||||||
static Node *
|
|
||||||
BuildBaseConstraint(Var *variable)
|
|
||||||
{
|
|
||||||
OpExpr *lessThanExpr = MakeOpExpression(variable, BTLessEqualStrategyNumber);
|
|
||||||
OpExpr *greaterThanExpr = MakeOpExpression(variable, BTGreaterEqualStrategyNumber);
|
|
||||||
|
|
||||||
Node *baseConstraint = make_and_qual((Node *) lessThanExpr, (Node *) greaterThanExpr);
|
|
||||||
|
|
||||||
return baseConstraint;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* MakeOpExpression builds an operator expression node. This operator expression
|
|
||||||
* implements the operator clause as defined by the variable and the strategy
|
|
||||||
* number. The function is copied from CitusDB's shard pruning logic.
|
|
||||||
*/
|
|
||||||
static OpExpr *
|
|
||||||
MakeOpExpression(Var *variable, int16 strategyNumber)
|
|
||||||
{
|
|
||||||
Oid typeId = variable->vartype;
|
|
||||||
Oid typeModId = variable->vartypmod;
|
|
||||||
Oid collationId = variable->varcollid;
|
|
||||||
|
|
||||||
Oid accessMethodId = BTREE_AM_OID;
|
|
||||||
|
|
||||||
/* Load the operator from system catalogs */
|
|
||||||
Oid operatorId = GetOperatorByType(typeId, accessMethodId, strategyNumber);
|
|
||||||
|
|
||||||
Const *constantValue = makeNullConst(typeId, typeModId, collationId);
|
|
||||||
|
|
||||||
/* Now make the expression with the given variable and a null constant */
|
|
||||||
OpExpr *expression = (OpExpr *) make_opclause(operatorId,
|
|
||||||
InvalidOid, /* no result type yet */
|
|
||||||
false, /* no return set */
|
|
||||||
(Expr *) variable,
|
|
||||||
(Expr *) constantValue,
|
|
||||||
InvalidOid, collationId);
|
|
||||||
|
|
||||||
/* Set implementing function id and result type */
|
|
||||||
expression->opfuncid = get_opcode(operatorId);
|
|
||||||
expression->opresulttype = get_func_rettype(expression->opfuncid);
|
|
||||||
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GetOperatorByType returns operator Oid for the given type, access method,
|
|
||||||
* and strategy number. Note that this function incorrectly errors out when
|
|
||||||
* the given type doesn't have its own operator but can use another compatible
|
|
||||||
* type's default operator. The function is copied from CitusDB's shard pruning
|
|
||||||
* logic.
|
|
||||||
*/
|
|
||||||
static Oid
|
|
||||||
GetOperatorByType(Oid typeId, Oid accessMethodId, int16 strategyNumber)
|
|
||||||
{
|
|
||||||
/* Get default operator class from pg_opclass */
|
|
||||||
Oid operatorClassId = GetDefaultOpClass(typeId, accessMethodId);
|
|
||||||
|
|
||||||
Oid operatorFamily = get_opclass_family(operatorClassId);
|
|
||||||
|
|
||||||
Oid operatorId = get_opfamily_member(operatorFamily, typeId, typeId, strategyNumber);
|
|
||||||
|
|
||||||
return operatorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* UpdateConstraint updates the base constraint with the given min/max values.
|
|
||||||
* The function is copied from CitusDB's shard pruning logic.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
UpdateConstraint(Node *baseConstraint, Datum minValue, Datum maxValue)
|
|
||||||
{
|
|
||||||
BoolExpr *andExpr = (BoolExpr *) baseConstraint;
|
|
||||||
Node *lessThanExpr = (Node *) linitial(andExpr->args);
|
|
||||||
Node *greaterThanExpr = (Node *) lsecond(andExpr->args);
|
|
||||||
|
|
||||||
Node *minNode = get_rightop((Expr *) greaterThanExpr);
|
|
||||||
Node *maxNode = get_rightop((Expr *) lessThanExpr);
|
|
||||||
|
|
||||||
Assert(IsA(minNode, Const));
|
|
||||||
Assert(IsA(maxNode, Const));
|
|
||||||
|
|
||||||
Const *minConstant = (Const *) minNode;
|
|
||||||
Const *maxConstant = (Const *) maxNode;
|
|
||||||
|
|
||||||
minConstant->constvalue = minValue;
|
|
||||||
maxConstant->constvalue = maxValue;
|
|
||||||
|
|
||||||
minConstant->constisnull = false;
|
|
||||||
maxConstant->constisnull = false;
|
|
||||||
|
|
||||||
minConstant->constbyval = true;
|
|
||||||
maxConstant->constbyval = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SelectedChunkSkipList constructs a new StripeSkipList in which the
|
* SelectedChunkSkipList constructs a new StripeSkipList in which the
|
||||||
* non-selected chunks are removed from the given stripeSkipList.
|
* non-selected chunks are removed from the given stripeSkipList.
|
||||||
|
|
Loading…
Reference in New Issue