📄 groupbynode.java
字号:
predicates, dataDictionary, (RequiredRowOrdering) null); // RESOLVE: NEED TO FACTOR IN COST OF SORTING AND FIGURE OUT HOW // MANY ROWS HAVE BEEN ELIMINATED. costEstimate = optimizer.newCostEstimate(); costEstimate.setCost(childResult.getCostEstimate().getEstimatedCost(), childResult.getCostEstimate().rowCount(), childResult.getCostEstimate().singleScanRowCount()); return this; } ResultColumnDescriptor[] makeResultDescriptors(ExecutionContext ec) { return childResult.makeResultDescriptors(ec); } /** * Return whether or not the underlying ResultSet tree will return * a single row, at most. * This is important for join nodes where we can save the extra next * on the right side if we know that it will return at most 1 row. * * @return Whether or not the underlying ResultSet tree will return a single row. * @exception StandardException Thrown on error */ public boolean isOneRowResultSet() throws StandardException { // Only consider scalar aggregates for now return ((groupingList == null) || (groupingList.size() == 0)); } /** * generate the sort result set operating over the source * resultset. Adds distinct aggregates to the sort if * necessary. * * @exception StandardException Thrown on error */ public void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { int orderingItem = 0; int aggInfoItem = 0; FormatableArrayHolder orderingHolder; /* Get the next ResultSet#, so we can number this ResultSetNode, its * ResultColumnList and ResultSet. */ assignResultSetNumber(); // Get the final cost estimate from the child. costEstimate = childResult.getFinalCostEstimate(); /* ** Get the column ordering for the sort. Note that ** for a scalar aggegate we may not have any ordering ** columns (if there are no distinct aggregates). ** WARNING: if a distinct aggregate is passed to ** SortResultSet it assumes that the last column ** is the distinct one. If this assumption changes ** then SortResultSet will have to change. */ orderingHolder = acb.getColumnOrdering(groupingList); if (addDistinctAggregate) { orderingHolder = acb.addColumnToOrdering( orderingHolder, addDistinctAggregateColumnNum); } if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON("AggregateTrace")) { StringBuffer s = new StringBuffer(); s.append("Group by column ordering is ("); ColumnOrdering[] ordering = (ColumnOrdering[])orderingHolder.getArray(ColumnOrdering.class); for (int i = 0; i < ordering.length; i++) { s.append(ordering[i].getColumnId()); s.append(" "); } s.append(")"); SanityManager.DEBUG("AggregateTrace", s.toString()); } } orderingItem = acb.addItem(orderingHolder); /* ** We have aggregates, so save the aggInfo ** struct in the activation and store the number */ if (SanityManager.DEBUG) { SanityManager.ASSERT(aggInfo != null, "aggInfo not set up as expected"); } aggInfoItem = acb.addItem(aggInfo); acb.pushGetResultSetFactoryExpression(mb); // Generate the child ResultSet childResult.generate(acb, mb); mb.push(isInSortedOrder); mb.push(aggInfoItem); mb.push(orderingItem); acb.pushThisAsActivation(mb); resultColumns.generateHolder(acb, mb); mb.push(resultColumns.getTotalColumnSize()); mb.push(resultSetNumber); /* Generate a (Distinct)ScalarAggregateResultSet if scalar aggregates */ if ((groupingList == null) || (groupingList.size() == 0)) { genScalarAggregateResultSet(acb, mb); } /* Generate a (Distinct)GroupedAggregateResultSet if grouped aggregates */ else { genGroupedAggregateResultSet(acb, mb); } } /** * Generate the code to evaluate scalar aggregates. * */ private void genScalarAggregateResultSet(ActivationClassBuilder acb, MethodBuilder mb) { /* Generate the (Distinct)ScalarAggregateResultSet: * arg1: childExpress - Expression for childResult * arg2: isInSortedOrder - true if source result set in sorted order * arg3: aggregateItem - entry in saved objects for the aggregates, * arg4: orderItem - entry in saved objects for the ordering * arg5: Activation * arg6: rowAllocator - method to construct rows for fetching * from the sort * arg7: row size * arg8: resultSetNumber * arg9: Whether or not to perform min optimization. * arg12: closeCleanup */ String resultSet = (addDistinctAggregate) ? "getDistinctScalarAggregateResultSet" : "getScalarAggregateResultSet"; mb.push(singleInputRowOptimization); mb.push(costEstimate.rowCount()); mb.push(costEstimate.getEstimatedCost()); closeMethodArgument(acb, mb); mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, resultSet, ClassName.NoPutResultSet, 12); } /** * Generate the code to evaluate grouped aggregates. * */ private void genGroupedAggregateResultSet(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { /* Generate the (Distinct)GroupedAggregateResultSet: * arg1: childExpress - Expression for childResult * arg2: isInSortedOrder - true if source result set in sorted order * arg3: aggregateItem - entry in saved objects for the aggregates, * arg4: orderItem - entry in saved objects for the ordering * arg5: Activation * arg6: rowAllocator - method to construct rows for fetching * from the sort * arg7: row size * arg8: resultSetNumber * arg11: closeCleanup */ String resultSet = (addDistinctAggregate) ? "getDistinctGroupedAggregateResultSet" : "getGroupedAggregateResultSet"; mb.push(costEstimate.rowCount()); mb.push(costEstimate.getEstimatedCost()); closeMethodArgument(acb, mb); mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, resultSet, ClassName.NoPutResultSet, 11); } /////////////////////////////////////////////////////////////// // // UTILITIES // /////////////////////////////////////////////////////////////// /** * Method for creating a new result column referencing * the one passed in. * * @param targetRC the source * @param dd * * @return the new result column * * @exception StandardException on error */ private ResultColumn getColumnReference(ResultColumn targetRC, DataDictionary dd) throws StandardException { ColumnReference tmpColumnRef; ResultColumn newRC; tmpColumnRef = (ColumnReference) getNodeFactory().getNode( C_NodeTypes.COLUMN_REFERENCE, targetRC.getName(), null, getContextManager()); tmpColumnRef.setSource(targetRC); tmpColumnRef.setType(targetRC.getExpressionType()); tmpColumnRef.setNestingLevel(this.getLevel()); tmpColumnRef.setSourceLevel(this.getLevel()); newRC = (ResultColumn) getNodeFactory().getNode( C_NodeTypes.RESULT_COLUMN, targetRC.getColumnName(), tmpColumnRef, getContextManager()); newRC.markGenerated(); newRC.bindResultColumnToExpression(); return newRC; } /** * Consider any optimizations after the optimizer has chosen a plan. * Optimizations include: * o min optimization for scalar aggregates * o max optimization for scalar aggregates * * @param selectHasPredicates true if SELECT containing this * vector/scalar aggregate has a restriction * * @return Nothing. * * @exception StandardException on error */ void considerPostOptimizeOptimizations(boolean selectHasPredicates) throws StandardException { /* Consider the optimization for min with asc index on that column or * max with desc index on that column: * o No group by * o One of: * o min/max(ColumnReference) is only aggregate && source is * ordered on the ColumnReference * o min/max(ConstantNode) * The optimization of the other way around (min with desc index or * max with asc index) has the same restrictions with the additional * temporary restriction of no qualifications at all (because * we don't have true backward scans). */ if (groupingList == null) { if (aggregateVector.size() == 1) { AggregateNode an = (AggregateNode) aggregateVector.elementAt(0); AggregateDefinition ad = an.getAggregateDefinition(); if (ad instanceof MaxMinAggregateDefinition) { if (an.getOperand() instanceof ColumnReference) { /* See if the underlying ResultSet tree * is ordered on the ColumnReference. */ ColumnReference[] crs = new ColumnReference[1]; crs[0] = (ColumnReference) an.getOperand(); Vector tableVector = new Vector(); boolean minMaxOptimizationPossible = isOrderedOn(crs, false, tableVector); if (SanityManager.DEBUG) { SanityManager.ASSERT(tableVector.size() <= 1, "bad number of FromBaseTables returned by isOrderedOn() -- "+tableVector.size()); } if (minMaxOptimizationPossible) { boolean ascIndex = true; int colNum = crs[0].getColumnNumber(); /* Check if we have an access path, this will be * null in a join case (See Beetle 4423) */ AccessPath accessPath= getTrulyTheBestAccessPath(); if (accessPath == null) return; IndexDescriptor id = accessPath. getConglomerateDescriptor(). getIndexDescriptor(); int[] keyColumns = id.baseColumnPositions(); boolean[] isAscending = id.isAscending(); for (int i = 0; i < keyColumns.length; i++) { /* in such a query: select min(c3) from * tab1 where c1 = 2 and c2 = 5, if prefix keys * have equality operator, then we can still use * the index. The checking of equality operator * has been done in isStrictlyOrderedOn. */ if (colNum == keyColumns[i]) { if (! isAscending[i]) ascIndex = false; break; } } FromBaseTable fbt = (FromBaseTable)tableVector.firstElement(); MaxMinAggregateDefinition temp = (MaxMinAggregateDefinition)ad; /* MAX ASC NULLABLE * ---- ---------- * TRUE TRUE TRUE/FALSE = Special Last Key Scan (ASC Index Last key with null skips) * TRUE FALSE TRUE/FALSE = JustDisableBulk(DESC index 1st key with null skips) * FALSE TRUE TRUE/FALSE = JustDisableBulk(ASC index 1st key) * FALSE FALSE TRUE/FALSE = Special Last Key Scan(Desc Index Last Key) */ if (((!temp.isMax()) && ascIndex) || ((temp.isMax()) && !ascIndex)) { fbt.disableBulkFetch(); singleInputRowOptimization = true; } /* ** Max optimization with asc index or min with ** desc index is currently more ** restrictive than otherwise. ** We are getting the store to return the last ** row from an index (for the time being, the ** store cannot do real backward scans). SO ** we cannot do this optimization if we have ** any predicates at all. */ else if (!selectHasPredicates && ((temp.isMax() && ascIndex) || (!temp.isMax() && !ascIndex ))) { fbt.disableBulkFetch(); fbt.doSpecialMaxScan(); singleInputRowOptimization = true; } } } else if (an.getOperand() instanceof ConstantNode) { singleInputRowOptimization = true; } } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -