use of org.voltdb.planner.parseinfo.StmtTableScan in project voltdb by VoltDB.
the class SubPlanAssembler method getAccessPlanForTable.
/**
* Given an access path, build the single-site or distributed plan that will
* assess the data from the table according to the path.
*
* @param table The table to get data from.
* @return The root of a plan graph to get the data.
*/
protected static AbstractPlanNode getAccessPlanForTable(JoinNode tableNode) {
StmtTableScan tableScan = tableNode.getTableScan();
// Access path to access the data in the table (index/scan/etc).
AccessPath path = tableNode.m_currentAccessPath;
assert (path != null);
// if no index, it is a sequential scan
if (path.index == null) {
return getScanAccessPlanForTable(tableScan, path);
}
return getIndexAccessPlanForTable(tableScan, path);
}
use of org.voltdb.planner.parseinfo.StmtTableScan in project voltdb by VoltDB.
the class MaterializedViewProcessor method findBestMatchIndexForMatviewMinOrMax.
// if the materialized view has MIN / MAX, try to find an index defined on the source table
// covering all group by cols / exprs to avoid expensive tablescan.
// For now, the only acceptable index is defined exactly on the group by columns IN ORDER.
// This allows the same key to be used to do lookups on the grouped table index and the
// base table index.
// TODO: More flexible (but usually less optimal*) indexes may be allowed here and supported
// in the EE in the future including:
// -- *indexes on the group keys listed out of order
// -- *indexes on the group keys as a prefix before other indexed values.
// -- (ENG-6511) indexes on the group keys PLUS the MIN/MAX argument value (to eliminate post-filtering)
// This function is mostly re-written for the fix of ENG-6511. --yzhang
private static Index findBestMatchIndexForMatviewMinOrMax(MaterializedViewInfo matviewinfo, Table srcTable, List<AbstractExpression> groupbyExprs, AbstractExpression minMaxAggExpr) {
CatalogMap<Index> allIndexes = srcTable.getIndexes();
StmtTableScan tableScan = new StmtTargetTableScan(srcTable);
// Candidate index. If we can find an index covering both group-by columns and aggExpr (optimal) then we will
// return immediately.
// If the index found covers only group-by columns (sub-optimal), we will first cache it here.
Index candidate = null;
for (Index index : allIndexes) {
// indexOptimalForMinMax == true if the index covered both the group-by columns and the min/max aggExpr.
boolean indexOptimalForMinMax = false;
// If minMaxAggExpr is not null, the diff can be zero or one.
// Otherwise, for a usable index, its number of columns must agree with that of the group-by columns.
final int diffAllowance = minMaxAggExpr == null ? 0 : 1;
// Get all indexed exprs if there is any.
String expressionjson = index.getExpressionsjson();
List<AbstractExpression> indexedExprs = null;
if (!expressionjson.isEmpty()) {
try {
indexedExprs = AbstractExpression.fromJSONArrayString(expressionjson, tableScan);
} catch (JSONException e) {
e.printStackTrace();
assert (false);
return null;
}
}
// Get source table columns.
List<Column> srcColumnArray = CatalogUtil.getSortedCatalogItems(srcTable.getColumns(), "index");
MatViewIndexMatchingGroupby matchingCase = null;
if (groupbyExprs == null) {
// This means group-by columns are all simple columns.
// It also means we can only access the group-by columns by colref.
List<ColumnRef> groupbyColRefs = CatalogUtil.getSortedCatalogItems(matviewinfo.getGroupbycols(), "index");
if (indexedExprs == null) {
matchingCase = MatViewIndexMatchingGroupby.GB_COL_IDX_COL;
// All the columns in the index are also simple columns, EASY! colref vs. colref
List<ColumnRef> indexedColRefs = CatalogUtil.getSortedCatalogItems(index.getColumns(), "index");
// indexedColRefs.size() == groupbyColRefs.size() + 1 (optimal, diffAllowance == 1)
if (isInvalidIndexCandidate(indexedColRefs.size(), groupbyColRefs.size(), diffAllowance)) {
continue;
}
if (!isGroupbyMatchingIndex(matchingCase, groupbyColRefs, null, indexedColRefs, null, null)) {
continue;
}
if (isValidIndexCandidateForMinMax(indexedColRefs.size(), groupbyColRefs.size(), diffAllowance)) {
if (!isIndexOptimalForMinMax(matchingCase, minMaxAggExpr, indexedColRefs, null, srcColumnArray)) {
continue;
}
indexOptimalForMinMax = true;
}
} else {
matchingCase = MatViewIndexMatchingGroupby.GB_COL_IDX_EXP;
// for index columns: convert tve => col
if (isInvalidIndexCandidate(indexedExprs.size(), groupbyColRefs.size(), diffAllowance)) {
continue;
}
if (!isGroupbyMatchingIndex(matchingCase, groupbyColRefs, null, null, indexedExprs, srcColumnArray)) {
continue;
}
if (isValidIndexCandidateForMinMax(indexedExprs.size(), groupbyColRefs.size(), diffAllowance)) {
if (!isIndexOptimalForMinMax(matchingCase, minMaxAggExpr, null, indexedExprs, null)) {
continue;
}
indexOptimalForMinMax = true;
}
}
} else {
matchingCase = MatViewIndexMatchingGroupby.GB_EXP_IDX_EXP;
// AND, indexedExprs must not be null in this case. (yeah!)
if (indexedExprs == null) {
continue;
}
if (isInvalidIndexCandidate(indexedExprs.size(), groupbyExprs.size(), diffAllowance)) {
continue;
}
if (!isGroupbyMatchingIndex(matchingCase, null, groupbyExprs, null, indexedExprs, null)) {
continue;
}
if (isValidIndexCandidateForMinMax(indexedExprs.size(), groupbyExprs.size(), diffAllowance)) {
if (!isIndexOptimalForMinMax(matchingCase, minMaxAggExpr, null, indexedExprs, null)) {
continue;
}
indexOptimalForMinMax = true;
}
}
// NOW index at least covered all group-by columns (sub-optimal candidate)
if (!index.getPredicatejson().isEmpty()) {
// Additional check for partial indexes to make sure matview WHERE clause
// covers the partial index predicate
List<AbstractExpression> coveringExprs = new ArrayList<>();
List<AbstractExpression> exactMatchCoveringExprs = new ArrayList<>();
try {
String encodedPredicate = matviewinfo.getPredicate();
if (!encodedPredicate.isEmpty()) {
String predicate = Encoder.hexDecodeToString(encodedPredicate);
AbstractExpression matViewPredicate = AbstractExpression.fromJSONString(predicate, tableScan);
coveringExprs.addAll(ExpressionUtil.uncombineAny(matViewPredicate));
}
} catch (JSONException e) {
e.printStackTrace();
assert (false);
return null;
}
String predicatejson = index.getPredicatejson();
if (!predicatejson.isEmpty() && !SubPlanAssembler.isPartialIndexPredicateCovered(tableScan, coveringExprs, predicatejson, exactMatchCoveringExprs)) {
// where clause -- give up on this index
continue;
}
}
// it is already the best index we can get, return immediately.
if (indexOptimalForMinMax) {
return index;
}
// otherwise wait to see if we can find something better!
candidate = index;
}
return candidate;
}
use of org.voltdb.planner.parseinfo.StmtTableScan in project voltdb by VoltDB.
the class ParsedUnionStmt method addStmtTablesFromChildren.
private void addStmtTablesFromChildren(HashMap<String, StmtTableScan> tableAliasMap) {
for (String alias : tableAliasMap.keySet()) {
StmtTableScan tableScan = tableAliasMap.get(alias);
if (m_tableAliasMap.get(alias) == null) {
m_tableAliasMap.put(alias, tableScan);
} else {
// if there is a duplicate table alias in the map,
// find a new unique name for the key
// the value in the map are more interesting
alias += "_" + System.currentTimeMillis();
HashMap<String, StmtTableScan> duplicates = new HashMap<String, StmtTableScan>();
duplicates.put(alias, tableScan);
addStmtTablesFromChildren(duplicates);
}
}
}
use of org.voltdb.planner.parseinfo.StmtTableScan in project voltdb by VoltDB.
the class ParsedSelectStmt method prepareMVBasedQueryFix.
/**
* Prepare for the mv based distributed query fix only if it might be required.
*/
private void prepareMVBasedQueryFix() {
// aggregation push down does not need reAggregation work.
if (m_hasComplexGroupby) {
m_mvFixInfo.setEdgeCaseQueryNoFixNeeded(false);
}
// that need to be fixed should not exceed one.
for (StmtTableScan mvTableScan : allScans()) {
Set<SchemaColumn> mvNewScanColumns = new HashSet<>();
Collection<SchemaColumn> columns = mvTableScan.getScanColumns();
// TB has no scan columns
if (columns != null) {
mvNewScanColumns.addAll(columns);
}
// also need to be checked.
if (m_mvFixInfo.processMVBasedQueryFix(mvTableScan, mvNewScanColumns, m_joinTree, m_aggResultColumns, groupByColumns())) {
break;
}
}
}
use of org.voltdb.planner.parseinfo.StmtTableScan in project voltdb by VoltDB.
the class ParsedSelectStmt method isPartitionColumnInWindowedAggregatePartitionByList.
/**
* Return true iff all the windowed partition expressions
* have a table partition column in their partition by list,
* and if there is one such windowed partition expression.
* If there are no windowed expressions, we return false.
* Note that there can only be one windowed
* expression currently, so this is more general than it needs to be.
*
* @return
*/
public boolean isPartitionColumnInWindowedAggregatePartitionByList() {
if (getWindowFunctionExpressions().size() == 0) {
return false;
}
// If we ever do, this should fail gracelessly.
assert (getWindowFunctionExpressions().size() == 1);
WindowFunctionExpression we = getWindowFunctionExpressions().get(0);
List<AbstractExpression> partitionByExprs = we.getPartitionByExpressions();
boolean foundPartExpr = false;
for (AbstractExpression ae : partitionByExprs) {
if (!(ae instanceof TupleValueExpression)) {
continue;
}
TupleValueExpression tve = (TupleValueExpression) ae;
String tableAlias = tve.getTableAlias();
String columnName = tve.getColumnName();
StmtTableScan scanTable = getStmtTableScanByAlias(tableAlias);
if (scanTable == null || scanTable.getPartitioningColumns() == null) {
continue;
}
boolean foundPartCol = false;
for (SchemaColumn pcol : scanTable.getPartitioningColumns()) {
if (pcol != null && pcol.getColumnName().equals(columnName)) {
foundPartCol = true;
break;
}
}
// in this windowed expression.
if (foundPartCol) {
foundPartExpr = true;
break;
}
}
return foundPartExpr;
}
Aggregations