📄 selectnode.java
字号:
return false; } /* Don't flatten if selectNode contains a group by or having clause */ if ((groupByList != null) || generatedForHavingClause) { return false; } /* Don't flatten if select list contains something that isn't cloneable. */ if (! resultColumns.isCloneable()) { return false; } /* Don't flatten if selectNode contains an aggregate */ if ((selectAggregates != null) && (selectAggregates.size() > 0)) { return false; } return true; } /** * Replace this SelectNode with a ProjectRestrictNode, * since it has served its purpose. * * @param origFromListSize The size of the original FROM list, before * generation of join tree. * @return ResultSetNode new ResultSetNode atop the query tree. * * @exception StandardException Thrown on error */ public ResultSetNode genProjectRestrict(int origFromListSize) throws StandardException { boolean orderingDependent = false; PredicateList restrictionList; ResultColumnList prRCList; ResultSetNode prnRSN; prnRSN = (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.PROJECT_RESTRICT_NODE, fromList.elementAt(0), /* Child ResultSet */ resultColumns, /* Projection */ whereClause, /* Restriction */ wherePredicates,/* Restriction as PredicateList */ selectSubquerys,/* Subquerys in Projection */ whereSubquerys, /* Subquerys in Restriction */ null, getContextManager() ); /* ** If we have aggregates OR a select list we want ** to generate a GroupByNode. In the case of a ** scalar aggregate we have no grouping columns. ** ** JRESOLVE: what about correlated aggregates from another ** block. */ if (((selectAggregates != null) && (selectAggregates.size() > 0)) || (groupByList != null)) { GroupByNode gbn = (GroupByNode) getNodeFactory().getNode( C_NodeTypes.GROUP_BY_NODE, prnRSN, groupByList, selectAggregates, null, getContextManager()); gbn.considerPostOptimizeOptimizations(originalWhereClause != null); gbn.assignCostEstimate(optimizer.getOptimizedCost()); groupByList = null; prnRSN = gbn.getParent(); // Remember if the result is dependent on the ordering orderingDependent = orderingDependent || gbn.getIsInSortedOrder(); } // if it is distinct, that must also be taken care of. if (isDistinct) { // We first verify that a distinct is valid on the // RCL. resultColumns.verifyAllOrderable(); /* See if we can push duplicate elimination into the store * via a hash scan. This is possible iff: * o A single table query * o We haven't merged the order by and distinct sorts. * (Results do not have to be in a particular order.) * o All entries in the select's RCL are ColumnReferences. * o No predicates (This is because we currently do not * differentiate between columns referenced in the select * list and columns referenced in other clauses. In other * words, the store will do duplicate elimination based on * all referenced columns.) * RESOLVE - We can change this to be all referenced columns * have to be in the select list. In that case, we need to * refine which predicates are allowed. Basically, all predicates * must have been pushed down to the index/table scan.(If we make * this change, then we need to verify that non of the columns in * the predicates are correlated columns.) * o NOTE: The implementation of isPossibleDistinctScan() will return * false if there is an IndexRowToBaseRow above the * FromBaseTable. This is because all of a table's columns must come * from the same conglomerate in order to get consistent data. */ boolean distinctScanPossible = false; if (origFromListSize == 1 && (! orderByAndDistinctMerged) && resultColumns.countNumberOfSimpleColumnReferences() == resultColumns.size()) { boolean simpleColumns = true; HashSet distinctColumns = new HashSet(); int size = resultColumns.size(); for (int i = 1; i <= size; i++) { BaseColumnNode bc = resultColumns.getResultColumn(i).getBaseColumnNode(); if (bc == null) { simpleColumns = false; break; } distinctColumns.add(bc); } if (simpleColumns && prnRSN.isPossibleDistinctScan(distinctColumns)) { prnRSN.markForDistinctScan(); distinctScanPossible = true; } } if (!distinctScanPossible) { /* We can't do a distinct scan. Determine if we can filter out * duplicates without a sorter. */ boolean inSortedOrder = isOrderedResult(resultColumns, prnRSN, !(orderByAndDistinctMerged)); prnRSN = (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.DISTINCT_NODE, prnRSN, new Boolean(inSortedOrder), null, getContextManager()); prnRSN.costEstimate = costEstimate.cloneMe(); // Remember if the result is dependent on the ordering orderingDependent = orderingDependent || inSortedOrder; } } /* Generate the OrderByNode if a sort is still required for * the order by. */ if (orderByList != null) { if (orderByList.getSortNeeded()) { prnRSN = (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.ORDER_BY_NODE, prnRSN, orderByList, null, getContextManager()); prnRSN.costEstimate = costEstimate.cloneMe(); } int orderBySelect = this.getResultColumns().getOrderBySelect(); if (orderBySelect > 0) { ResultColumnList selectRCs = prnRSN.getResultColumns().copyListAndObjects(); int wholeSize = selectRCs.size(); for (int i = wholeSize - 1; orderBySelect > 0; i--, orderBySelect--) selectRCs.removeElementAt(i); selectRCs.genVirtualColumnNodes(prnRSN, prnRSN.getResultColumns()); prnRSN = (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.PROJECT_RESTRICT_NODE, prnRSN, selectRCs, null, null, null, null, null, getContextManager()); } } if (!(orderByList != null && orderByList.getSortNeeded()) && orderByQuery) { // Remember if the result is dependent on the ordering orderingDependent = true; } /* If the result is ordering dependent, then we must * tell the underlying tree. At minimum, this means no * group fetch on an index under an IndexRowToBaseRow * since that could lead to incorrect results. (Bug 2347.) */ if (orderingDependent) { prnRSN.markOrderingDependent(); } /* Set the cost of this node in the generated node */ prnRSN.costEstimate = costEstimate.cloneMe(); return prnRSN; } /** * Is the result of this node an ordered result set. An ordered result set * means that the results from this node will come in a known sorted order. * This means that the data is ordered according to the order of the elements in the RCL. * Today, the data is considered ordered if: * o The RCL is composed entirely of CRs or ConstantNodes * o The underlying tree is ordered on the CRs in the order in which * they appear in the RCL, taking equality predicates into account. * Future Enhancements: * o The prefix will not be required to be in order. (We will need to * reorder the RCL and generate a PRN with an RCL in the expected order.) * * @return boolean Whether or not this node returns an ordered result set. * * @exception StandardException Thrown on error */ private boolean isOrderedResult(ResultColumnList resultColumns, ResultSetNode newTopRSN, boolean permuteOrdering) throws StandardException { int rclSize = resultColumns.size(); /* Not ordered if RCL contains anything other than a ColumnReference * or a ConstantNode. */ int numCRs = 0; for (int index = 0; index < rclSize; index++) { ResultColumn rc = (ResultColumn) resultColumns.elementAt(index); if (rc.getExpression() instanceof ColumnReference) { numCRs++; } else if (! (rc.getExpression() instanceof ConstantNode)) { return false; } } // Corner case, all constants if (numCRs == 0) { return true; } ColumnReference[] crs = new ColumnReference[numCRs]; // Now populate the CR array and see if ordered int crsIndex = 0; for (int index = 0; index < rclSize; index++) { ResultColumn rc = (ResultColumn) resultColumns.elementAt(index); if (rc.getExpression() instanceof ColumnReference) { crs[crsIndex++] = (ColumnReference) rc.getExpression(); } } return newTopRSN.isOrderedOn(crs, permuteOrdering, (Vector)null); } /** * Ensure that the top of the RSN tree has a PredicateList. * * @param numTables The number of tables in the query. * @return ResultSetNode A RSN tree with a node which has a PredicateList on top. * * @exception StandardException Thrown on error */ public ResultSetNode ensurePredicateList(int numTables) throws StandardException { return this; } /** * Optimize this SelectNode. This means choosing the best access path * for each table, among other things. * * @param dataDictionary The DataDictionary to use for optimization * @param predicateList The predicate list to optimize against * @param outerRows The number of outer joining rows * * @return ResultSetNode The top of the optimized tree * * @exception StandardException Thrown on error */ public ResultSetNode optimize(DataDictionary dataDictionary, PredicateList predicateList, double outerRows) throws StandardException { Optimizer optimizer; /* Optimize any subquerys before optimizing the underlying result set */ /* selectSubquerys is always allocated at bind() time */ if (SanityManager.DEBUG) SanityManager.ASSERT(selectSubquerys != null, "selectSubquerys is expected to be non-null"); /* If this select node is the child of an outer node that is * being optimized, we can get here multiple times (once for * every permutation that is done for the outer node). With * DERBY-805, we can add optimizable predicates to the WHERE * list as part of this method; thus, before proceeding we * need go through and remove any opt predicates that we added * to our WHERE list the last time we were here; if we don't * do that, we'll end up with the same predicates in our * WHERE list multiple times, which can lead to incorrect * optimization. */ if (wherePredicates != null) { // Iterate backwards because we might be deleting entries. for (int i = wherePredicates.size() - 1; i >= 0; i--) { if (((Predicate)wherePredicates.elementAt(i)).isScopedForPush()) wherePredicates.removeOptPredicate(i); } } /* Get a new optimizer */ /* With DERBY-805 we take any optimizable predicates that * were pushed into this node and we add them to the list of * predicates that we pass to the optimizer, thus allowing * the optimizer to use them when choosing an access path * for this SELECT node. We do that by adding the predicates * to our WHERE list, since the WHERE predicate list is what * we pass to the optimizer for this select node (see below). * We have to pass the WHERE list directly (as opposed to * passing a copy) because the optimizer is only created one * time; it then uses the list we pass it for the rest of the * optimization phase and finally for "modifyAccessPaths()". * Since the optimizer can update/modify the list based on the * WHERE predicates (such as by adding internal predicates or * by modifying the actual predicates themselves), we need * those changes to be applied to the WHERE list directly for * subsequent processing (esp. for modification of the access * path). Note that by adding outer opt predicates directly * to the WHERE list, we're changing the semantics of this * SELECT node. This is only temporary, though--once the * optimizer is done with all of its work, any predicates * that were pushed here will have been pushed even further * down and thus will have been removed from the WHERE list * (if it's not possible to push them further down, then they * shouldn't have made it this far to begin with). */ if (predicateList != null) { if (wherePredicates == null) { wherePredicates = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); } Predicate pred = null; int sz = predicateList.size(); for (int i = sz - 1; i >= 0; i--) { // We can tell if a predicate was pushed into this select // node because it will have been "scoped" for this node; // see Predicate.getScopedPredForResultSet() for more on // what scoping is and how it's done. pred = (Predicate)predicateList.getOptPredicate(i); if (pred.isScopedForPush()) { // If we're pushing the predicate down here, we have to // remove it from the predicate list of the node above // this select, in order to keep in line with established // push 'protocol'. wherePredicates.addOptPredicate(pred); predicateList.removeOptPredicate(pred); } } } optimizer = getOptimizer(fromList, wherePredicates, dataDictionary, orderByList); optimizer.setOuterRows(outerRows); /* Optimize this SelectNode */ while (optimizer.getNextPermutation()) { while (optimizer.getNextDecoratedPermutation()) { optimizer.costPermutation(); } } /* Get the cost */ costEstimate = optimizer.getOptimizedCost(); /* Update row counts if this is a scalar aggregate */ if ((selectAggregates != null) && (selectAggregates.size() > 0)) { costEstimate.setEstimatedRowCount((long) outerRows); costEstimate.setSingleScanRowCount(1); } selectSubquerys.optimize(dataDictionary, costEstimate.rowCount());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -