[teiid-commits] teiid SVN: r3062 - 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
Tue Apr 5 12:24:59 EDT 2011


Author: shawkins
Date: 2011-04-05 12:24:58 -0400 (Tue, 05 Apr 2011)
New Revision: 3062

Modified:
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java
Log:
TEIID-1545 expanding the order by optimization to compensate for unrelated sorts and pushdown of order by regardless of the use of limits

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java	2011-04-05 14:48:29 UTC (rev 3061)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java	2011-04-05 16:24:58 UTC (rev 3062)
@@ -211,7 +211,7 @@
         	if (NewCalculateCostUtil.usesKey(sourceNode, expressions, metadata)) {
                 joinNode.setProperty(joinNode.getFirstChild() == childNode ? NodeConstants.Info.IS_LEFT_DISTINCT : NodeConstants.Info.IS_RIGHT_DISTINCT, true);
         	}
-	        if (attemptPush && RuleRaiseAccess.canRaiseOverSort(sourceNode, metadata, capFinder, sortNode, null)) {
+	        if (attemptPush && RuleRaiseAccess.canRaiseOverSort(sourceNode, metadata, capFinder, sortNode, null, false)) {
 	            sourceNode.getFirstChild().addAsParent(sortNode);
 	            
 	            if (needsCorrection) {

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-04-05 14:48:29 UTC (rev 3061)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanSorts.java	2011-04-05 16:24:58 UTC (rev 3062)
@@ -58,10 +58,10 @@
 			AnalysisRecord analysisRecord, CommandContext context)
 			throws QueryPlannerException, QueryMetadataException,
 			TeiidComponentException {
-		return optimizeSorts(false, plan, plan);
+		return optimizeSorts(false, plan, plan, metadata, capabilitiesFinder, analysisRecord);
 	}
 
-	private PlanNode optimizeSorts(boolean parentBlocking, PlanNode node, PlanNode root) {
+	private PlanNode optimizeSorts(boolean parentBlocking, PlanNode node, PlanNode root, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
 		node = NodeEditor.findNodePreOrder(node, 
 				NodeConstants.Types.SORT 
 				| NodeConstants.Types.DUP_REMOVE 
@@ -79,10 +79,8 @@
 			}
 			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);
+			} else {
+				root = checkForProjectOptimization(node, root, metadata, capFinder, record);
 			}
 			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);
@@ -207,21 +205,32 @@
 			break;
 		}
 		for (PlanNode child : node.getChildren()) {
-			root = optimizeSorts(parentBlocking, child, root);
+			root = optimizeSorts(parentBlocking, child, root, metadata, capFinder, record);
 		}
 		return root;
 	}
 
-	private PlanNode checkForProjectOptimization(PlanNode node, PlanNode root,
-			PlanNode parent) {
-		if (parent.getType() != NodeConstants.Types.TUPLE_LIMIT) {
-			return root;
-		}
+	private PlanNode checkForProjectOptimization(PlanNode node, PlanNode root, 
+			QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
 		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) {
+		PlanNode parent = node.getParent();
+		boolean raiseAccess = false;
+		//special check for unrelated order by compensation
+		if (projectNode.getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode.getFirstChild(), metadata, capFinder, node, record, true)) {
+			projectNode = NodeEditor.findNodePreOrder(projectNode, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
+			if (projectNode == null) {
+				return root; //shouldn't happen
+			}
+			raiseAccess = true;
+		} else if (projectNode.getType() == NodeConstants.Types.PROJECT && projectNode.getFirstChild() != null) {
+			raiseAccess = projectNode.getFirstChild().getType() == NodeConstants.Types.ACCESS 
+				&& RuleRaiseAccess.canRaiseOverSort(projectNode.getFirstChild(), metadata, capFinder, node, record, false);
+			
+			//if we can't raise the access node and this doesn't have a limit, there's no point in optimizing
+			if (!raiseAccess && (parent == null || parent.getType() != NodeConstants.Types.TUPLE_LIMIT)) {
+				return root;
+			}
+		} else {
 			return root;
 		}
 		List<SingleElementSymbol> childOutputCols = (List<SingleElementSymbol>) projectNode.getFirstChild().getProperty(Info.OUTPUT_COLS);
@@ -230,13 +239,21 @@
 		if (!childOutputCols.containsAll(orderByKeys)) {
 			return root;
 		}
-		//move the project before the ordered limit
-		NodeEditor.removeChildNode(node, projectNode);
-		if (parent.getParent() != null) {
-			parent.addAsParent(node);
+		NodeEditor.removeChildNode(projectNode.getParent(), projectNode);
+		if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT && parent.getParent() != null) {
+			parent.addAsParent(projectNode);
 		} else {
-			root = projectNode;
-			projectNode.addFirstChild(parent);
+			if (parent == null) {
+				root = projectNode;
+			}
+			if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT) {
+				if (root == parent) {
+					root = projectNode; 
+				}
+				projectNode.addFirstChild(parent);
+			} else {
+				projectNode.addFirstChild(node);
+			}
 		}
 		List<SingleElementSymbol> orderByOutputSymbols = (List<SingleElementSymbol>) node.getProperty(Info.OUTPUT_COLS);
 		if (node.hasBooleanProperty(Info.UNRELATED_SORT)) {
@@ -250,7 +267,16 @@
 		projectNode.setProperty(Info.OUTPUT_COLS, orderByOutputSymbols);
 		projectNode.setProperty(Info.PROJECT_COLS, orderByOutputSymbols);
 		node.setProperty(Info.OUTPUT_COLS, childOutputCols);
-		parent.setProperty(Info.OUTPUT_COLS, childOutputCols);
+		if (parent != null) {
+			parent.setProperty(Info.OUTPUT_COLS, childOutputCols);
+		}
+		if (raiseAccess) {
+			PlanNode accessNode = node.getFirstChild();
+			root = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record);
+			if (accessNode.getParent().getType() == NodeConstants.Types.TUPLE_LIMIT) {
+				root = RulePushLimit.raiseAccessOverLimit(root, accessNode, metadata, capFinder, accessNode.getParent());
+			}
+		}
 		return root;
 	}
 

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2011-04-05 14:48:29 UTC (rev 3061)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java	2011-04-05 16:24:58 UTC (rev 3062)
@@ -154,7 +154,7 @@
             }
             case NodeConstants.Types.SORT:
             {         
-                if (canRaiseOverSort(accessNode, metadata, capFinder, parentNode, record)) {
+                if (canRaiseOverSort(accessNode, metadata, capFinder, parentNode, record, false)) {
                     return performRaise(rootNode, accessNode, parentNode);
                 }
                 return null;
@@ -333,7 +333,7 @@
     static boolean canRaiseOverSort(PlanNode accessNode,
                                    QueryMetadataInterface metadata,
                                    CapabilitiesFinder capFinder,
-                                   PlanNode parentNode, AnalysisRecord record) throws QueryMetadataException,
+                                   PlanNode parentNode, AnalysisRecord record, boolean compensateForUnrelated) throws QueryMetadataException,
                                                        TeiidComponentException {
         // Find the model for this node by getting ACCESS node's model
         Object modelID = getModelIDFromAccess(accessNode, metadata);
@@ -395,11 +395,10 @@
         	return false;
         }
         
-        /* If we have an unrelated sort it cannot be pushed down if it's not supported by the source
-         * 
-         * TODO: we should be able to work this
-         */
-        if (parentNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT) && !CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_UNRELATED, modelID, metadata, capFinder)) {
+        if (parentNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT) 
+        		&& !CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_UNRELATED, modelID, metadata, capFinder)
+        		&& NodeEditor.findParent(accessNode, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE) == null
+        		&& !compensateForUnrelated) {
         	return false;
         }
         

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java	2011-04-05 14:48:29 UTC (rev 3061)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java	2011-04-05 16:24:58 UTC (rev 3062)
@@ -56,6 +56,7 @@
 import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.processor.relational.AccessNode;
 import org.teiid.query.processor.relational.DependentAccessNode;
+import org.teiid.query.processor.relational.EnhancedSortMergeJoinStrategy;
 import org.teiid.query.processor.relational.GroupingNode;
 import org.teiid.query.processor.relational.JoinNode;
 import org.teiid.query.processor.relational.JoinStrategy;
@@ -63,7 +64,6 @@
 import org.teiid.query.processor.relational.NestedLoopJoinStrategy;
 import org.teiid.query.processor.relational.NestedTableJoinStrategy;
 import org.teiid.query.processor.relational.NullNode;
-import org.teiid.query.processor.relational.EnhancedSortMergeJoinStrategy;
 import org.teiid.query.processor.relational.PlanExecutionNode;
 import org.teiid.query.processor.relational.ProjectIntoNode;
 import org.teiid.query.processor.relational.ProjectNode;
@@ -1557,33 +1557,6 @@
     }    
 
     /** 
-     * Tests that query transformation order by is discarded by
-     * user order by, and that user order by is discarded because
-     * of the function in the query transformation 
-     */
-    @Test public void testPushOrderByThroughFrame3() {
-        ProcessorPlan plan = helpPlan("SELECT e, e2 FROM vm1.g16 ORDER BY e2", FakeMetadataFactory.example1Cached(), //$NON-NLS-1$
-            new String[] { "SELECT e1, e2 FROM pm3.g1"}); //$NON-NLS-1$
-
-        checkNodeTypes(plan, new int[] {
-            1,      // Access
-            0,      // DependentAccess
-            0,      // DependentSelect
-            0,      // DependentProject
-            0,      // DupRemove
-            0,      // Grouping
-            0,      // NestedLoopJoinStrategy
-            0,      // MergeJoinStrategy
-            0,      // Null
-            0,      // PlanExecution
-            1,      // Project
-            0,      // Select
-            1,      // Sort
-            0       // UnionAll
-        });                                    
-    } 
-
-    /** 
      * Tests that a user's order by does not get pushed to the source
      * if there is a UNION in the query transformation 
      */
@@ -3610,11 +3583,11 @@
         checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN);     
     }
     
-    @Test public void testBQT9500_126() {
+    @Test public void testBQT9500_126() throws Exception {
         String sql = "SELECT IntKey, LongNum, expr FROM (SELECT IntKey, LongNum, concat(LongNum, 'abc') FROM BQT2.SmallA ) AS x ORDER BY IntKey"; //$NON-NLS-1$
         ProcessorPlan plan = helpPlan(sql, FakeMetadataFactory.exampleBQTCached(), 
                                       new String[] { 
-                                          "SELECT IntKey, LongNum FROM BQT2.SmallA" }); //$NON-NLS-1$ 
+                                          "SELECT g_0.IntKey AS c_0, g_0.LongNum AS c_1 FROM BQT2.SmallA AS g_0 ORDER BY c_0" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ 
 
         checkNodeTypes(plan, new int[] {
                                         1,      // Access
@@ -3629,7 +3602,7 @@
                                         0,      // PlanExecution
                                         1,      // Project
                                         0,      // Select
-                                        1,      // Sort
+                                        0,      // Sort
                                         0       // UnionAll
         });                                    
         

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java	2011-04-05 14:48:29 UTC (rev 3061)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSortOptimization.java	2011-04-05 16:24:58 UTC (rev 3062)
@@ -26,10 +26,12 @@
 import static org.teiid.query.optimizer.TestOptimizer.*;
 
 import org.junit.Test;
+import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
 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.optimizer.capabilities.SourceCapabilities.Capability;
 import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.processor.relational.LimitNode;
 import org.teiid.query.processor.relational.ProjectNode;
@@ -176,7 +178,7 @@
     
     @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$
+        String sql = "select e1, (select e1 from pm2.g1 where e2 = x.e2) from pm1.g1 as x order by e1 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$
@@ -193,5 +195,42 @@
         
         assertTrue(plan.getRootNode() instanceof LimitNode);
     }
+    
+    @Test public void testProjectionRaisingWithAccess() throws Exception { 
+        // Create query 
+        String sql = "select e1, (select e1 from pm2.g1 where e2 = x.e2) as z from pm1.g1 as x order by e1"; //$NON-NLS-1$
 
+        helpPlan(sql, FakeMetadataFactory.example1Cached(), null, TestOptimizer.getGenericFinder(), 
+                                      new String[] {"SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm1.g1 AS g_0 ORDER BY c_0"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+    }
+    
+    @Test public void testProjectionRaisingForUnrelatedWithLimit() throws Exception { 
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        caps.setCapabilitySupport(Capability.ROW_LIMIT, true);
+        caps.setCapabilitySupport(Capability.QUERY_ORDERBY, true);
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+        capFinder.addCapabilities("pm2", caps); //$NON-NLS-1$
+        
+        String sql = "select (select e1 from pm2.g1 where e2 = x.e2) as z from pm1.g1 as x order by e1 limit 1"; //$NON-NLS-1$
+
+        helpPlan(sql, FakeMetadataFactory.example1Cached(), null, capFinder, 
+                                      new String[] {"SELECT pm1.g1.e1, pm1.g1.e2 FROM pm1.g1 ORDER BY pm1.g1.e1 LIMIT 1"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+    }
+    
+    @Test public void testProjectionRaisingForUnrelated() throws Exception { 
+        FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+        BasicSourceCapabilities caps = new BasicSourceCapabilities();
+        caps.setCapabilitySupport(Capability.ROW_LIMIT, true);
+        caps.setCapabilitySupport(Capability.QUERY_ORDERBY, true);
+        capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+        capFinder.addCapabilities("pm2", caps); //$NON-NLS-1$
+        
+        String sql = "select e2 from pm1.g1 as x order by e1"; //$NON-NLS-1$
+
+        helpPlan(sql, FakeMetadataFactory.example1Cached(), null, capFinder, 
+                                      new String[] {"SELECT pm1.g1.e2, pm1.g1.e1 FROM pm1.g1 ORDER BY pm1.g1.e1"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+    }
+
+
 }



More information about the teiid-commits mailing list