use of org.voltdb.plannodes.IndexScanPlanNode in project voltdb by VoltDB.
the class InlineAggregation method inlineAggregationApply.
AbstractPlanNode inlineAggregationApply(AbstractPlanNode plan) {
// check for an aggregation of the right form
if (!(plan instanceof AggregatePlanNode)) {
return plan;
}
assert (plan.getChildCount() == 1);
AggregatePlanNode aggplan = (AggregatePlanNode) plan;
// Assuming all AggregatePlanNode has not been inlined before this microoptimization
AbstractPlanNode child = aggplan.getChild(0);
// EE Currently support: seqscan + indexscan
if (child.getPlanNodeType() != PlanNodeType.SEQSCAN && child.getPlanNodeType() != PlanNodeType.INDEXSCAN && child.getPlanNodeType() != PlanNodeType.NESTLOOP && child.getPlanNodeType() != PlanNodeType.NESTLOOPINDEX) {
return plan;
}
if (child.getPlanNodeType() == PlanNodeType.INDEXSCAN) {
// Currently do not conflict with the optimized MIN/MAX
// because of the big amount of tests changed.
IndexScanPlanNode isp = (IndexScanPlanNode) child;
LimitPlanNode limit = (LimitPlanNode) isp.getInlinePlanNode(PlanNodeType.LIMIT);
if (limit != null && (aggplan.isTableMin() || aggplan.isTableMax())) {
// Optimized MIN/MAX
if (limit.getLimit() == 1 && limit.getOffset() == 0) {
return plan;
}
}
}
// Inline aggregate node
AbstractPlanNode parent = null;
if (aggplan.getParentCount() == 1) {
parent = aggplan.getParent(0);
}
child.addInlinePlanNode(aggplan);
child.clearParents();
if (parent != null) {
parent.replaceChild(aggplan, child);
}
return child;
}
use of org.voltdb.plannodes.IndexScanPlanNode in project voltdb by VoltDB.
the class SubPlanAssembler method getIndexAccessPlanForTable.
/**
* Get an index scan access plan for a table.
*
* @param tableAliasIndex The table to get data from.
* @param path The access path to access the data in the table (index/scan/etc).
* @return An index scan plan node OR,
in one edge case, an NLIJ of a MaterializedScan and an index scan plan node.
*/
private static AbstractPlanNode getIndexAccessPlanForTable(StmtTableScan tableScan, AccessPath path) {
// now assume this will be an index scan and get the relevant index
Index index = path.index;
IndexScanPlanNode scanNode = new IndexScanPlanNode(tableScan, index);
AbstractPlanNode resultNode = scanNode;
// set sortDirection here because it might be used for IN list
scanNode.setSortDirection(path.sortDirection);
// the one element of indexExprs.
for (AbstractExpression expr : path.indexExprs) {
if (path.lookupType == IndexLookupType.GEO_CONTAINS) {
scanNode.addSearchKeyExpression(expr);
scanNode.addCompareNotDistinctFlag(false);
continue;
}
AbstractExpression exprRightChild = expr.getRight();
assert (exprRightChild != null);
if (expr.getExpressionType() == ExpressionType.COMPARE_IN) {
// Replace this method's result with an injected NLIJ.
resultNode = injectIndexedJoinWithMaterializedScan(exprRightChild, scanNode);
// Extract a TVE from the LHS MaterializedScan for use by the IndexScan in its new role.
MaterializedScanPlanNode matscan = (MaterializedScanPlanNode) resultNode.getChild(0);
AbstractExpression elemExpr = matscan.getOutputExpression();
assert (elemExpr != null);
// Replace the IN LIST condition in the end expression referencing all the list elements
// with a more efficient equality filter referencing the TVE for each element in turn.
replaceInListFilterWithEqualityFilter(path.endExprs, exprRightChild, elemExpr);
// Set up the similar VectorValue --> TVE replacement of the search key expression.
exprRightChild = elemExpr;
}
if (exprRightChild instanceof AbstractSubqueryExpression) {
// DEAD CODE with the guards on index: ENG-8203
assert (false);
}
scanNode.addSearchKeyExpression(exprRightChild);
// If the index expression is an "IS NOT DISTINCT FROM" comparison, let the NULL values go through. (ENG-11096)
scanNode.addCompareNotDistinctFlag(expr.getExpressionType() == ExpressionType.COMPARE_NOTDISTINCT);
}
// create the IndexScanNode with all its metadata
scanNode.setLookupType(path.lookupType);
scanNode.setBindings(path.bindings);
scanNode.setEndExpression(ExpressionUtil.combinePredicates(path.endExprs));
scanNode.setPredicate(path.otherExprs);
// Propagate the sorting information
// into the scan node from the access path.
// The initial expression is needed to control a (short?) forward scan to adjust the start of a reverse
// iteration after it had to initially settle for starting at "greater than a prefix key".
scanNode.setInitialExpression(ExpressionUtil.combinePredicates(path.initialExpr));
scanNode.setSkipNullPredicate();
scanNode.setEliminatedPostFilters(path.eliminatedPostExprs);
if (scanNode instanceof IndexSortablePlanNode) {
IndexUseForOrderBy indexUse = ((IndexSortablePlanNode) scanNode).indexUse();
indexUse.setWindowFunctionUsesIndex(path.m_windowFunctionUsesIndex);
indexUse.setSortOrderFromIndexScan(path.sortDirection);
indexUse.setWindowFunctionIsCompatibleWithOrderBy(path.m_stmtOrderByIsCompatible);
indexUse.setFinalExpressionOrderFromIndexScan(path.m_finalExpressionOrder);
}
return resultNode;
}
use of org.voltdb.plannodes.IndexScanPlanNode in project voltdb by VoltDB.
the class ScanDeterminizer method recursivelyApply.
private static AbstractPlanNode recursivelyApply(AbstractPlanNode plan) {
assert (plan != null);
// depth first:
// Find Sequential Scan node.
// Replace with any unique tree index scan if possible.
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 (replaced);
}
// skip the meat if this isn't a scan node
if (!(plan instanceof SeqScanPlanNode)) {
return plan;
}
SeqScanPlanNode scanNode = (SeqScanPlanNode) plan;
if (scanNode.isSubQuery()) {
// This is a sub-query and can't have indexes
return plan;
}
// got here? we're got ourselves a sequential scan over a real table
assert (scanNode.getChildCount() == 0);
StmtTableScan tableScan = scanNode.getTableScan();
assert (tableScan != null);
Index indexToScan = null;
// does anything for performance at all.
for (Index index : tableScan.getIndexes()) {
// skip non-unique indexes
if (index.getUnique() == false) {
continue;
} else // skip hash indexes
if (index.getType() != IndexType.BALANCED_TREE.getValue()) {
continue;
} else // skip partial indexes
if (!index.getPredicatejson().isEmpty()) {
continue;
} else if (indexToScan == null || CatalogUtil.getCatalogIndexSize(indexToScan) > CatalogUtil.getCatalogIndexSize(index)) {
indexToScan = index;
}
}
if (indexToScan == null) {
return plan;
}
// make an index node from the scan node
IndexScanPlanNode indexScanNode = new IndexScanPlanNode(scanNode, null, indexToScan, SortDirectionType.ASC);
indexScanNode.setForDeterminismOnly();
return indexScanNode;
}
use of org.voltdb.plannodes.IndexScanPlanNode in project voltdb by VoltDB.
the class TestMultipleOuterJoinPlans method verifyJoinNode.
private void verifyJoinNode(AbstractPlanNode n, PlanNodeType nodeType, JoinType joinType, ExpressionType preJoinExpressionType, ExpressionType joinExpressionType, ExpressionType whereExpressionType, PlanNodeType outerNodeType, PlanNodeType innerNodeType, String outerTableAlias, String innerTableAlias) {
assertEquals(nodeType, n.getPlanNodeType());
AbstractJoinPlanNode jn = (AbstractJoinPlanNode) n;
assertEquals(joinType, jn.getJoinType());
if (preJoinExpressionType != null) {
assertEquals(preJoinExpressionType, jn.getPreJoinPredicate().getExpressionType());
} else {
assertNull(jn.getPreJoinPredicate());
}
if (joinExpressionType != null) {
assertEquals(joinExpressionType, jn.getJoinPredicate().getExpressionType());
} else {
assertNull(jn.getJoinPredicate());
}
if (whereExpressionType != null) {
assertEquals(whereExpressionType, jn.getWherePredicate().getExpressionType());
} else {
assertNull(jn.getWherePredicate());
}
assertEquals(outerNodeType, jn.getChild(0).getPlanNodeType());
if (outerTableAlias != null) {
assertEquals(outerTableAlias, ((AbstractScanPlanNode) jn.getChild(0)).getTargetTableAlias());
}
if (nodeType == PlanNodeType.NESTLOOP) {
assertEquals(innerNodeType, jn.getChild(1).getPlanNodeType());
}
if (innerTableAlias != null) {
if (nodeType == PlanNodeType.NESTLOOP) {
assertEquals(innerTableAlias, ((AbstractScanPlanNode) jn.getChild(1)).getTargetTableAlias());
} else {
IndexScanPlanNode sn = (IndexScanPlanNode) jn.getInlinePlanNode(PlanNodeType.INDEXSCAN);
assertEquals(innerTableAlias, sn.getTargetTableAlias());
}
}
}
use of org.voltdb.plannodes.IndexScanPlanNode in project voltdb by VoltDB.
the class TestPlansJoin method perJoinOpTestIndexJoinConditions.
private void perJoinOpTestIndexJoinConditions(JoinOp joinOp) {
String query;
AbstractPlanNode pn;
AbstractPlanNode node;
NestLoopPlanNode nlj;
NestLoopIndexPlanNode nlij;
IndexScanPlanNode indexScan;
AbstractExpression predicate;
SeqScanPlanNode seqScan;
query = "SELECT * FROM R3, R2 WHERE R3.A" + joinOp + "R2.A AND R3.C > 0 AND R2.C >= 5";
pn = compileToTopDownTree(query, 4, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOPINDEX, PlanNodeType.SEQSCAN);
node = followAssertedLeftChain(pn, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOPINDEX);
nlij = (NestLoopIndexPlanNode) node;
assertNull(nlij.getJoinPredicate());
indexScan = nlij.getInlineIndexScan();
assertEquals(IndexLookupType.EQ, indexScan.getLookupType());
predicate = indexScan.getEndExpression();
assertExprTopDownTree(predicate, joinOp.toOperator(), ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_TUPLE);
predicate = indexScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHAN, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
seqScan = (SeqScanPlanNode) nlij.getChild(0);
predicate = seqScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHANOREQUALTO, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
query = "SELECT * FROM R3 JOIN R2 ON R3.A" + joinOp + "R2.A WHERE R3.C > 0 AND R2.C >= 5";
pn = compileToTopDownTree(query, 4, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOPINDEX, PlanNodeType.SEQSCAN);
node = followAssertedLeftChain(pn, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOPINDEX);
nlij = (NestLoopIndexPlanNode) node;
assertNull(nlij.getJoinPredicate());
indexScan = nlij.getInlineIndexScan();
assertEquals(IndexLookupType.EQ, indexScan.getLookupType());
predicate = indexScan.getEndExpression();
assertExprTopDownTree(predicate, joinOp.toOperator(), ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_TUPLE);
predicate = indexScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHAN, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
seqScan = (SeqScanPlanNode) nlij.getChild(0);
predicate = seqScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHANOREQUALTO, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
query = "SELECT * FROM R3 JOIN R2 USING(A) WHERE R3.C > 0 AND R2.C >= 5";
pn = compileToTopDownTree(query, 3, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOPINDEX, PlanNodeType.SEQSCAN);
node = followAssertedLeftChain(pn, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOPINDEX);
nlij = (NestLoopIndexPlanNode) node;
assertNull(nlij.getJoinPredicate());
indexScan = nlij.getInlineIndexScan();
assertEquals(IndexLookupType.EQ, indexScan.getLookupType());
predicate = indexScan.getEndExpression();
assertExprTopDownTree(predicate, joinOp.toOperator(), ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_TUPLE);
predicate = indexScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHAN, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
seqScan = (SeqScanPlanNode) nlij.getChild(0);
predicate = seqScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHANOREQUALTO, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
query = "SELECT * FROM R3 JOIN R2 ON R3.A" + joinOp + " R2.A JOIN R1 ON R2.A" + joinOp + "R1.A WHERE R3.C > 0 AND R2.C >= 5";
pn = compileToTopDownTree(query, 7, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOP, PlanNodeType.NESTLOOPINDEX, PlanNodeType.SEQSCAN, PlanNodeType.SEQSCAN);
node = followAssertedLeftChain(pn, PlanNodeType.SEND, PlanNodeType.PROJECTION, PlanNodeType.NESTLOOP);
nlj = (NestLoopPlanNode) node;
assertNull(nlj.getPreJoinPredicate());
predicate = nlj.getJoinPredicate();
assertExprTopDownTree(predicate, joinOp.toOperator(), ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_TUPLE);
assertNull(nlj.getWherePredicate());
nlij = (NestLoopIndexPlanNode) nlj.getChild(0);
indexScan = nlij.getInlineIndexScan();
assertEquals(IndexLookupType.EQ, indexScan.getLookupType());
predicate = indexScan.getEndExpression();
assertExprTopDownTree(predicate, joinOp.toOperator(), ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_TUPLE);
predicate = indexScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHAN, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
seqScan = (SeqScanPlanNode) nlij.getChild(0);
predicate = seqScan.getPredicate();
assertExprTopDownTree(predicate, ExpressionType.COMPARE_GREATERTHANOREQUALTO, ExpressionType.VALUE_TUPLE, ExpressionType.VALUE_CONSTANT);
}
Aggregations