private boolean hasEqualityConstraints(int startPos, int endPos) { ScanRanges ranges = context.getScanRanges(); // If a GROUP BY is being done, then the rows are ordered according to the GROUP BY key, // not by the original row key order of the table (see PHOENIX-3451). // We check each GROUP BY expression to see if it only references columns that are // matched by equality constraints, in which case the expression itself would be constant. // FIXME: this only recognizes row key columns that are held constant, not all columns. // FIXME: we should optimize out any GROUP BY or ORDER BY expression which is deemed to // be held constant based on the WHERE clause. if (!groupBy.isEmpty()) { for (int pos = startPos; pos < endPos; pos++) { IsConstantVisitor visitor = new IsConstantVisitor(this.projector, ranges); List<Expression> groupByExpressions = groupBy.getExpressions(); if (pos >= groupByExpressions.size()) { // sanity check - shouldn't be necessary return false; } Expression groupByExpression = groupByExpressions.get(pos); if (groupByExpression.getDeterminism().ordinal() > Determinism.PER_STATEMENT.ordinal()) { return false; } Boolean isConstant = groupByExpression.accept(visitor); if (!Boolean.TRUE.equals(isConstant)) { return false; } } return true; } for (int pos = startPos; pos < endPos; pos++) { if (!ranges.hasEqualityConstraint(pos)) { return false; } } return true; }
public OrderPreservingTracker( StatementContext context, GroupBy groupBy, Ordering ordering, int nNodes, TupleProjector projector) { this.context = context; if (groupBy.isEmpty()) { PTable table = context.getResolver().getTables().get(0).getTable(); this.isOrderPreserving = table.rowKeyOrderOptimizable(); boolean isSalted = table.getBucketNum() != null; boolean isMultiTenant = context.getConnection().getTenantId() != null && table.isMultiTenant(); boolean isSharedViewIndex = table.getViewIndexId() != null; // TODO: util for this offset, as it's computed in numerous places this.pkPositionOffset = (isSalted ? 1 : 0) + (isMultiTenant ? 1 : 0) + (isSharedViewIndex ? 1 : 0); } else { this.isOrderPreserving = true; this.pkPositionOffset = 0; } this.groupBy = groupBy; this.visitor = new TrackOrderPreservingExpressionVisitor(projector); this.orderPreservingInfos = Lists.newArrayListWithExpectedSize(nNodes); this.ordering = ordering; this.projector = projector; }
protected void explain(String prefix, List<String> planSteps) { StringBuilder buf = new StringBuilder(prefix); ScanRanges scanRanges = context.getScanRanges(); boolean hasSkipScanFilter = false; if (scanRanges.isEverything()) { buf.append("FULL SCAN "); } else { hasSkipScanFilter = explainSkipScan(buf); } buf.append("OVER " + tableRef.getTable().getName().getString()); if (!scanRanges.isPointLookup()) { appendKeyRanges(buf); } planSteps.add(buf.toString()); Scan scan = context.getScan(); Filter filter = scan.getFilter(); PageFilter pageFilter = null; if (filter != null) { int offset = 0; boolean hasFirstKeyOnlyFilter = false; String filterDesc = ""; if (hasSkipScanFilter) { if (filter instanceof FilterList) { List<Filter> filterList = ((FilterList) filter).getFilters(); if (filterList.get(0) instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; offset = 1; } if (filterList.size() > offset + 1) { filterDesc = filterList.get(offset + 1).toString(); if (filterList.size() > offset + 2) { pageFilter = (PageFilter) filterList.get(offset + 2); } } } } else if (filter instanceof FilterList) { List<Filter> filterList = ((FilterList) filter).getFilters(); if (filterList.get(0) instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; offset = 1; } if (filterList.size() > offset) { filterDesc = filterList.get(offset).toString(); if (filterList.size() > offset + 1) { pageFilter = (PageFilter) filterList.get(offset + 1); } } } else { if (filter instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; } else { filterDesc = filter.toString(); } } if (filterDesc.length() > 0) { planSteps.add( " SERVER FILTER BY " + (hasFirstKeyOnlyFilter ? "FIRST KEY ONLY AND " : "") + filterDesc); } else if (hasFirstKeyOnlyFilter) { planSteps.add(" SERVER FILTER BY FIRST KEY ONLY"); } if (pageFilter != null) { planSteps.add(" SERVER " + pageFilter.getPageSize() + " ROW LIMIT"); } } groupBy.explain(planSteps); }