[teiid-commits] teiid SVN: r3031 - in trunk/engine/src: test/java/org/teiid/query/optimizer and 1 other directory.
teiid-commits at lists.jboss.org
teiid-commits at lists.jboss.org
Wed Mar 23 23:37:12 EDT 2011
Author: shawkins
Date: 2011-03-23 23:37:10 -0400 (Wed, 23 Mar 2011)
New Revision: 3031
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java
Log:
TEIID-1529 adding a targeted optimization so that limiting can occur before projection if possible
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java 2011-03-23 19:28:44 UTC (rev 3030)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java 2011-03-24 03:37:10 UTC (rev 3031)
@@ -39,6 +39,7 @@
import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
import org.teiid.query.processor.relational.MergeJoinStrategy.SortOption;
import org.teiid.query.sql.lang.OrderBy;
+import org.teiid.query.sql.lang.OrderByItem;
import org.teiid.query.sql.lang.SetQuery;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.util.CommandContext;
@@ -46,6 +47,8 @@
/**
* Attempts to minimize the cost of sorting operations across the plan.
+ *
+ * Must be run after output elements are assigned
*/
public class RulePlanSorts implements OptimizerRule {
@@ -76,6 +79,10 @@
}
if (mergeSortWithDupRemoval(node)) {
node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true);
+ } else if (node.getParent() != null) {
+ //if we are not distinct and there is a limit, the projection could be deferred
+ PlanNode parent = node.getParent();
+ root = checkForProjectOptimization(node, root, parent);
}
List<SingleElementSymbol> orderColumns = ((OrderBy)node.getProperty(NodeConstants.Info.SORT_ORDER)).getSortKeys();
PlanNode possibleSort = NodeEditor.findNodePreOrder(node, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS);
@@ -205,6 +212,48 @@
return root;
}
+ private PlanNode checkForProjectOptimization(PlanNode node, PlanNode root,
+ PlanNode parent) {
+ if (parent.getType() != NodeConstants.Types.TUPLE_LIMIT) {
+ return root;
+ }
+ PlanNode projectNode = node.getFirstChild();
+ //if (child.getType() == NodeConstants.Types.ACCESS) {
+ //TODO: there should be a cost based evaluation if this looks like ACCESS->PROJECT and we attempt to raise project expressions
+ //}
+ if (projectNode.getType() != NodeConstants.Types.PROJECT || projectNode.getFirstChild() == null) {
+ return root;
+ }
+ List<SingleElementSymbol> childOutputCols = (List<SingleElementSymbol>) projectNode.getFirstChild().getProperty(Info.OUTPUT_COLS);
+ OrderBy orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
+ List<SingleElementSymbol> orderByKeys = orderBy.getSortKeys();
+ if (!childOutputCols.containsAll(orderByKeys)) {
+ return root;
+ }
+ //move the project before the ordered limit
+ NodeEditor.removeChildNode(node, projectNode);
+ if (parent.getParent() != null) {
+ parent.addAsParent(node);
+ } else {
+ root = projectNode;
+ projectNode.addFirstChild(parent);
+ }
+ List<SingleElementSymbol> orderByOutputSymbols = (List<SingleElementSymbol>) node.getProperty(Info.OUTPUT_COLS);
+ if (node.hasBooleanProperty(Info.UNRELATED_SORT)) {
+ node.setProperty(Info.UNRELATED_SORT, false);
+ //update sort order
+ for (OrderByItem item : orderBy.getOrderByItems()) {
+ int index = childOutputCols.indexOf(item.getSymbol());
+ item.setExpressionPosition(index);
+ }
+ }
+ projectNode.setProperty(Info.OUTPUT_COLS, orderByOutputSymbols);
+ projectNode.setProperty(Info.PROJECT_COLS, orderByOutputSymbols);
+ node.setProperty(Info.OUTPUT_COLS, childOutputCols);
+ parent.setProperty(Info.OUTPUT_COLS, childOutputCols);
+ return root;
+ }
+
private boolean mergeSortWithDupRemovalAcrossSource(PlanNode toTest) {
PlanNode source = NodeEditor.findNodePreOrder(toTest, NodeConstants.Types.SOURCE, NodeConstants.Types.ACCESS | NodeConstants.Types.JOIN);
return source != null && mergeSortWithDupRemoval(source);
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java 2011-03-23 19:28:44 UTC (rev 3030)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java 2011-03-24 03:37:10 UTC (rev 3031)
@@ -22,12 +22,18 @@
package org.teiid.query.optimizer;
+import static org.junit.Assert.*;
import static org.teiid.query.optimizer.TestOptimizer.*;
import org.junit.Test;
+import org.teiid.query.optimizer.TestOptimizer.DupRemoveSortNode;
import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
+import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
import org.teiid.query.processor.ProcessorPlan;
+import org.teiid.query.processor.relational.LimitNode;
+import org.teiid.query.processor.relational.ProjectNode;
+import org.teiid.query.processor.relational.RelationalPlan;
import org.teiid.query.unittest.FakeMetadataFactory;
@@ -167,5 +173,25 @@
});
checkNodeTypes(plan, new int[] {0}, new Class[] {DupRemoveSortNode.class});
}
+
+ @Test public void testProjectionRaisingWithLimit() {
+ // Create query
+ String sql = "select e1, (select e1 from pm2.g1 where e2 = x.e2) from pm1.g1 as x order by e2 limit 2"; //$NON-NLS-1$
+ RelationalPlan plan = (RelationalPlan)helpPlan(sql, FakeMetadataFactory.example1Cached(), null, new DefaultCapabilitiesFinder(),
+ new String[] {"SELECT pm1.g1.e1, pm1.g1.e2 FROM pm1.g1"}, TestOptimizer.SHOULD_SUCCEED); //$NON-NLS-1$
+
+ assertTrue(plan.getRootNode() instanceof ProjectNode);
+ }
+
+ @Test public void testProjectionRaisingWithLimit1() {
+ // Create query
+ String sql = "select (select e1 from pm2.g1 where e2 = x.e2) as z from pm1.g1 as x order by z limit 2"; //$NON-NLS-1$
+
+ RelationalPlan plan = (RelationalPlan)helpPlan(sql, FakeMetadataFactory.example1Cached(), null, new DefaultCapabilitiesFinder(),
+ new String[] {"SELECT pm1.g1.e2 FROM pm1.g1"}, TestOptimizer.SHOULD_SUCCEED); //$NON-NLS-1$
+
+ assertTrue(plan.getRootNode() instanceof LimitNode);
+ }
+
}
More information about the teiid-commits
mailing list