Merge pull request #1369 from citusdata/featurefix/better-range-pruning

Improve / Fix range pruning
pull/1323/head
Andres Freund 2017-04-28 17:45:58 -07:00 committed by GitHub
commit 0cc9171984
1 changed files with 132 additions and 81 deletions

View File

@ -186,6 +186,9 @@ static List * PruneWithBoundaries(DistTableCacheEntry *cacheEntry,
static List * ExhaustivePrune(DistTableCacheEntry *cacheEntry, static List * ExhaustivePrune(DistTableCacheEntry *cacheEntry,
ClauseWalkerContext *context, ClauseWalkerContext *context,
PruningInstance *prune); PruningInstance *prune);
static bool ExhaustivePruneOne(ShardInterval *curInterval,
ClauseWalkerContext *context,
PruningInstance *prune);
static int UpperShardBoundary(Datum partitionColumnValue, static int UpperShardBoundary(Datum partitionColumnValue,
ShardInterval **shardIntervalCache, ShardInterval **shardIntervalCache,
int shardCount, FunctionCallInfoData *compareFunction, int shardCount, FunctionCallInfoData *compareFunction,
@ -894,14 +897,26 @@ PruneOne(DistTableCacheEntry *cacheEntry, ClauseWalkerContext *context,
} }
/* /*
* If previous pruning method yielded a single shard, we could also * If previous pruning method yielded a single shard, and the table is not
* attempt range based pruning to exclude it further. But that seems * hash partitioned, attempt range based pruning to exclude it further.
* rarely useful in practice, and thus likely a waste of runtime and code *
* complexity. * That's particularly important in particular for subquery pushdown,
* where it's very common to have a user specified equality restriction,
* and a range based restriction for shard boundaries, added by the
* subquery machinery.
*/ */
if (shardInterval) if (shardInterval)
{ {
return list_make1(shardInterval); if (context->partitionMethod != DISTRIBUTE_BY_HASH &&
ExhaustivePruneOne(shardInterval, context, prune))
{
return NIL;
}
else
{
/* no chance to prune further, return */
return list_make1(shardInterval);
}
} }
/* /*
@ -1158,9 +1173,19 @@ PruneWithBoundaries(DistTableCacheEntry *cacheEntry, ClauseWalkerContext *contex
} }
if (prune->greaterConsts) if (prune->greaterConsts)
{ {
lowerBound = prune->greaterConsts->constvalue; /*
lowerBoundInclusive = false; * Use the more restrictive one, if both greater and greaterEqual
hasLowerBound = true; * constraints are specified.
*/
if (!hasLowerBound ||
PerformValueCompare(compareFunctionCall,
prune->greaterConsts->constvalue,
lowerBound) >= 0)
{
lowerBound = prune->greaterConsts->constvalue;
lowerBoundInclusive = false;
hasLowerBound = true;
}
} }
if (prune->lessEqualConsts) if (prune->lessEqualConsts)
{ {
@ -1170,9 +1195,19 @@ PruneWithBoundaries(DistTableCacheEntry *cacheEntry, ClauseWalkerContext *contex
} }
if (prune->lessConsts) if (prune->lessConsts)
{ {
upperBound = prune->lessConsts->constvalue; /*
upperBoundInclusive = false; * Use the more restrictive one, if both less and lessEqual
hasUpperBound = true; * constraints are specified.
*/
if (!hasUpperBound ||
PerformValueCompare(compareFunctionCall,
prune->lessConsts->constvalue,
upperBound) <= 0)
{
upperBound = prune->lessConsts->constvalue;
upperBoundInclusive = false;
hasUpperBound = true;
}
} }
Assert(hasLowerBound || hasUpperBound); Assert(hasLowerBound || hasUpperBound);
@ -1232,88 +1267,104 @@ ExhaustivePrune(DistTableCacheEntry *cacheEntry, ClauseWalkerContext *context,
PruningInstance *prune) PruningInstance *prune)
{ {
List *remainingShardList = NIL; List *remainingShardList = NIL;
FunctionCallInfo compareFunctionCall = &context->compareIntervalFunctionCall;
int shardCount = cacheEntry->shardIntervalArrayLength; int shardCount = cacheEntry->shardIntervalArrayLength;
ShardInterval **sortedShardIntervalArray = cacheEntry->sortedShardIntervalArray; ShardInterval **sortedShardIntervalArray = cacheEntry->sortedShardIntervalArray;
int curIdx = 0; int curIdx = 0;
for (curIdx = 0; curIdx < shardCount; curIdx++) for (curIdx = 0; curIdx < shardCount; curIdx++)
{ {
Datum compareWith = 0;
ShardInterval *curInterval = sortedShardIntervalArray[curIdx]; ShardInterval *curInterval = sortedShardIntervalArray[curIdx];
/* NULL boundaries can't be compared to */ if (!ExhaustivePruneOne(curInterval, context, prune))
if (!curInterval->minValueExists || !curInterval->maxValueExists)
{ {
remainingShardList = lappend(remainingShardList, curInterval); remainingShardList = lappend(remainingShardList, curInterval);
continue;
} }
if (prune->equalConsts)
{
compareWith = prune->equalConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
compareWith,
curInterval->minValue) < 0)
{
continue;
}
if (PerformValueCompare(compareFunctionCall,
compareWith,
curInterval->maxValue) > 0)
{
continue;
}
}
if (prune->greaterEqualConsts)
{
compareWith = prune->greaterEqualConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->maxValue,
compareWith) < 0)
{
continue;
}
}
if (prune->greaterConsts)
{
compareWith = prune->greaterConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->maxValue,
compareWith) <= 0)
{
continue;
}
}
if (prune->lessEqualConsts)
{
compareWith = prune->lessEqualConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->minValue,
compareWith) > 0)
{
continue;
}
}
if (prune->lessConsts)
{
compareWith = prune->lessConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->minValue,
compareWith) >= 0)
{
continue;
}
}
remainingShardList = lappend(remainingShardList, curInterval);
} }
return remainingShardList; return remainingShardList;
} }
/*
* ExhaustivePruneOne returns true if curInterval is pruned away, false
* otherwise.
*/
static bool
ExhaustivePruneOne(ShardInterval *curInterval,
ClauseWalkerContext *context,
PruningInstance *prune)
{
FunctionCallInfo compareFunctionCall = &context->compareIntervalFunctionCall;
Datum compareWith = 0;
/* NULL boundaries can't be compared to */
if (!curInterval->minValueExists || !curInterval->maxValueExists)
{
return false;
}
if (prune->equalConsts)
{
compareWith = prune->equalConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
compareWith,
curInterval->minValue) < 0)
{
return true;
}
if (PerformValueCompare(compareFunctionCall,
compareWith,
curInterval->maxValue) > 0)
{
return true;
}
}
if (prune->greaterEqualConsts)
{
compareWith = prune->greaterEqualConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->maxValue,
compareWith) < 0)
{
return true;
}
}
if (prune->greaterConsts)
{
compareWith = prune->greaterConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->maxValue,
compareWith) <= 0)
{
return true;
}
}
if (prune->lessEqualConsts)
{
compareWith = prune->lessEqualConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->minValue,
compareWith) > 0)
{
return true;
}
}
if (prune->lessConsts)
{
compareWith = prune->lessConsts->constvalue;
if (PerformValueCompare(compareFunctionCall,
curInterval->minValue,
compareWith) >= 0)
{
return true;
}
}
return false;
}