use of org.voltdb.plannodes.TableCountPlanNode in project voltdb by VoltDB.
the class ReplaceWithIndexCounter method recursivelyApply.
@Override
protected AbstractPlanNode recursivelyApply(AbstractPlanNode plan) {
assert (plan != null);
// depth first:
// find AggregatePlanNode with exactly one child
// where that child is an AbstractScanPlanNode.
// Replace any qualifying AggregatePlanNode / AbstractScanPlanNode pair
// with an IndexCountPlanNode or TableCountPlanNode
ArrayList<AbstractPlanNode> children = new ArrayList<AbstractPlanNode>();
for (int i = 0; i < plan.getChildCount(); i++) children.add(plan.getChild(i));
for (AbstractPlanNode child : children) {
// TODO this will break when children feed multiple parents
AbstractPlanNode newChild = recursivelyApply(child);
// Do a graft into the (parent) plan only if a replacement for a child was found.
if (newChild == child) {
continue;
}
boolean replaced = plan.replaceChild(child, newChild);
assert (true == replaced);
}
// check for an aggregation of the right form
if ((plan instanceof AggregatePlanNode) == false)
return plan;
assert (plan.getChildCount() == 1);
AggregatePlanNode aggplan = (AggregatePlanNode) plan;
// ENG-6131 fixed here.
if (!(aggplan.isTableCountStar() || aggplan.isTableNonDistinctCountConstant() || aggplan.isTableCountNonDistinctNullableColumn())) {
return plan;
}
AbstractPlanNode child = plan.getChild(0);
// A table count can replace a seq scan only if it has no predicates.
if (child instanceof SeqScanPlanNode) {
if (((SeqScanPlanNode) child).getPredicate() != null) {
return plan;
}
AbstractExpression postPredicate = aggplan.getPostPredicate();
if (postPredicate != null) {
List<AbstractExpression> aggList = postPredicate.findAllAggregateSubexpressions();
boolean allCountStar = true;
for (AbstractExpression expr : aggList) {
if (expr.getExpressionType() != ExpressionType.AGGREGATE_COUNT_STAR) {
allCountStar = false;
break;
}
}
if (allCountStar) {
return plan;
}
}
if (hasInlineLimit(aggplan)) {
// table count EE executor does not handle inline limit stuff
return plan;
}
return new TableCountPlanNode((AbstractScanPlanNode) child, aggplan);
}
// Otherwise, optimized counts only replace particular cases of index scan.
if ((child instanceof IndexScanPlanNode) == false)
return plan;
IndexScanPlanNode isp = (IndexScanPlanNode) child;
// Guard against (possible future?) cases of indexable subquery.
if (((IndexScanPlanNode) child).isSubQuery()) {
return plan;
}
// except those (post-)predicates are artifact predicates we added for reverse scan purpose only
if (isp.getPredicate() != null && !isp.isPredicatesOptimizableForAggregate()) {
return plan;
}
// With no start or end keys, there's not much a counting index can do.
if (isp.getEndExpression() == null && isp.getSearchKeyExpressions().size() == 0) {
if (hasInlineLimit(aggplan)) {
return plan;
}
return new TableCountPlanNode(isp, aggplan);
}
// check for the index's support for counting
Index idx = isp.getCatalogIndex();
if (!idx.getCountable()) {
return plan;
}
// The core idea is that counting index needs to know the start key and end key to
// jump to to get counts instead of actually doing any scanning.
// Options to be determined are:
// - whether each of the start/end keys is missing, partial (a prefix of a compund key), or complete,
// - whether the count should include or exclude entries exactly matching each of the start/end keys.
// Not all combinations of these options are supported;
// unsupportable cases cause the factory method to return null.
IndexCountPlanNode countingPlan = IndexCountPlanNode.createOrNull(isp, aggplan);
if (countingPlan == null) {
return plan;
}
return countingPlan;
}
use of org.voltdb.plannodes.TableCountPlanNode in project voltdb by VoltDB.
the class TestPlansSubQueries method testPartitionedGroupByWithoutAggregate.
public void testPartitionedGroupByWithoutAggregate() {
AbstractPlanNode pn;
List<AbstractPlanNode> planNodes;
// group by non-partition column, no pushed down
planNodes = compileToFragments("SELECT * FROM (SELECT C FROM P1 GROUP BY C) T1");
assertEquals(2, planNodes.size());
pn = planNodes.get(0).getChild(0);
checkSeqScan(pn, "T1");
pn = pn.getChild(0);
assertTrue(pn instanceof HashAggregatePlanNode);
pn = planNodes.get(1).getChild(0);
checkPrimaryKeyIndexScan(pn, "P1");
// count(*), no pushed down
planNodes = compileToFragments("SELECT count(*) FROM (SELECT c FROM P1 GROUP BY c) T1");
assertEquals(2, planNodes.size());
pn = planNodes.get(0).getChild(0);
assertTrue(pn instanceof TableCountPlanNode);
pn = pn.getChild(0);
assertTrue(pn instanceof HashAggregatePlanNode);
pn = planNodes.get(1).getChild(0);
checkPrimaryKeyIndexScan(pn, "P1");
// group by partition column, pushed down
planNodes = compileToFragments("SELECT * FROM (SELECT A FROM P1 GROUP BY A) T1");
assertEquals(2, planNodes.size());
pn = planNodes.get(0).getChild(0);
assertTrue(pn instanceof ProjectionPlanNode);
assertTrue(pn.getChild(0) instanceof ReceivePlanNode);
pn = planNodes.get(1).getChild(0);
checkSeqScan(pn, "T1");
pn = pn.getChild(0);
checkPrimaryKeyIndexScan(pn, "P1");
planNodes = compileToFragments("SELECT count(*) FROM (SELECT A FROM P1 GROUP BY A) T1");
assertEquals(2, planNodes.size());
pn = planNodes.get(0).getChild(0);
assertTrue(pn.getChild(0) instanceof ReceivePlanNode);
pn = planNodes.get(1).getChild(0);
assertTrue(pn instanceof TableCountPlanNode);
pn = pn.getChild(0);
checkPrimaryKeyIndexScan(pn, "P1");
}
use of org.voltdb.plannodes.TableCountPlanNode in project voltdb by VoltDB.
the class TestPushDownAggregates method checkPushedDown.
private void checkPushedDown(List<AbstractPlanNode> pn, boolean isAggInlined, ExpressionType[] aggTypes, ExpressionType[] pushDownTypes, boolean hasProjectionNode) {
// Aggregate push down check has to run on two fragments
assertTrue(pn.size() == 2);
AbstractPlanNode p = pn.get(0).getChild(0);
;
if (hasProjectionNode) {
// Complex aggregation or optimized AVG
assertTrue(p instanceof ProjectionPlanNode);
p = p.getChild(0);
}
assertTrue(p instanceof AggregatePlanNode);
String fragmentString = p.toJSONString();
ExpressionType[] topTypes = (pushDownTypes != null) ? pushDownTypes : aggTypes;
for (ExpressionType type : topTypes) {
assertTrue(fragmentString.contains("\"AGGREGATE_TYPE\":\"" + type.toString() + "\""));
}
// Check the pushed down aggregation
p = pn.get(1).getChild(0);
if (pushDownTypes == null) {
assertTrue(p instanceof AbstractScanPlanNode);
return;
}
if (isAggInlined) {
// See ENG-6131
if (p instanceof TableCountPlanNode) {
return;
}
assertTrue(p instanceof AbstractScanPlanNode);
assertTrue(p.getInlinePlanNode(PlanNodeType.AGGREGATE) != null || p.getInlinePlanNode(PlanNodeType.HASHAGGREGATE) != null);
if (p.getInlinePlanNode(PlanNodeType.AGGREGATE) != null) {
p = p.getInlinePlanNode(PlanNodeType.AGGREGATE);
} else {
p = p.getInlinePlanNode(PlanNodeType.HASHAGGREGATE);
}
} else {
assertTrue(p instanceof AggregatePlanNode);
}
fragmentString = p.toJSONString();
for (ExpressionType type : aggTypes) {
assertTrue(fragmentString.contains("\"AGGREGATE_TYPE\":\"" + type.toString() + "\""));
}
}
use of org.voltdb.plannodes.TableCountPlanNode in project voltdb by VoltDB.
the class TestPlansCount method testTableCount.
public void testTableCount() {
List<AbstractPlanNode> pn = compileToFragments("SELECT count(ID) from P1");
AbstractPlanNode p = pn.get(0).getChild(0);
assertTrue(p instanceof AggregatePlanNode);
p = pn.get(1).getChild(0);
assertTrue(p instanceof TableCountPlanNode);
}
use of org.voltdb.plannodes.TableCountPlanNode in project voltdb by VoltDB.
the class TestPlansCount method testCountStar003.
// Test subquery temp table count
public void testCountStar003() {
List<AbstractPlanNode> pn = compileToFragments("select count(*) from (SELECT count(*) from T1) Temp");
AbstractPlanNode p = pn.get(0).getChild(0);
assertTrue(p instanceof TableCountPlanNode);
p = p.getChild(0);
assertTrue(p instanceof TableCountPlanNode);
pn = compileToFragments("select count(1) from (SELECT count(*) from T1) Temp");
p = pn.get(0).getChild(0);
assertTrue(p instanceof TableCountPlanNode);
p = p.getChild(0);
assertTrue(p instanceof TableCountPlanNode);
}
Aggregations