[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