Search in sources :

Example 1 with TableCountPlanNode

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;
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) AggregatePlanNode(org.voltdb.plannodes.AggregatePlanNode) IndexScanPlanNode(org.voltdb.plannodes.IndexScanPlanNode) ArrayList(java.util.ArrayList) Index(org.voltdb.catalog.Index) TableCountPlanNode(org.voltdb.plannodes.TableCountPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) IndexCountPlanNode(org.voltdb.plannodes.IndexCountPlanNode) AbstractExpression(org.voltdb.expressions.AbstractExpression)

Example 2 with TableCountPlanNode

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");
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) MergeReceivePlanNode(org.voltdb.plannodes.MergeReceivePlanNode) ReceivePlanNode(org.voltdb.plannodes.ReceivePlanNode) HashAggregatePlanNode(org.voltdb.plannodes.HashAggregatePlanNode) TableCountPlanNode(org.voltdb.plannodes.TableCountPlanNode) ProjectionPlanNode(org.voltdb.plannodes.ProjectionPlanNode)

Example 3 with TableCountPlanNode

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() + "\""));
    }
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) AbstractScanPlanNode(org.voltdb.plannodes.AbstractScanPlanNode) AggregatePlanNode(org.voltdb.plannodes.AggregatePlanNode) ExpressionType(org.voltdb.types.ExpressionType) ProjectionPlanNode(org.voltdb.plannodes.ProjectionPlanNode) TableCountPlanNode(org.voltdb.plannodes.TableCountPlanNode)

Example 4 with TableCountPlanNode

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);
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) AggregatePlanNode(org.voltdb.plannodes.AggregatePlanNode) TableCountPlanNode(org.voltdb.plannodes.TableCountPlanNode)

Example 5 with 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);
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) TableCountPlanNode(org.voltdb.plannodes.TableCountPlanNode)

Aggregations

AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)8 TableCountPlanNode (org.voltdb.plannodes.TableCountPlanNode)8 AggregatePlanNode (org.voltdb.plannodes.AggregatePlanNode)5 ProjectionPlanNode (org.voltdb.plannodes.ProjectionPlanNode)2 ArrayList (java.util.ArrayList)1 Index (org.voltdb.catalog.Index)1 AbstractExpression (org.voltdb.expressions.AbstractExpression)1 AbstractScanPlanNode (org.voltdb.plannodes.AbstractScanPlanNode)1 HashAggregatePlanNode (org.voltdb.plannodes.HashAggregatePlanNode)1 IndexCountPlanNode (org.voltdb.plannodes.IndexCountPlanNode)1 IndexScanPlanNode (org.voltdb.plannodes.IndexScanPlanNode)1 MergeReceivePlanNode (org.voltdb.plannodes.MergeReceivePlanNode)1 ReceivePlanNode (org.voltdb.plannodes.ReceivePlanNode)1 SeqScanPlanNode (org.voltdb.plannodes.SeqScanPlanNode)1 ExpressionType (org.voltdb.types.ExpressionType)1