[teiid-commits] teiid SVN: r4038 - 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
Thu Apr 26 15:58:31 EDT 2012


Author: shawkins
Date: 2012-04-26 15:58:31 -0400 (Thu, 26 Apr 2012)
New Revision: 4038

Modified:
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseNull.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestUnionPlanning.java
Log:
TEIID-1993 optimizing dup remove in more situations

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleAssignOutputElements.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -161,8 +161,27 @@
 	                    } 
 					}
 	            }
+		    case NodeConstants.Types.DUP_REMOVE:
+		    	if (root.getType() == NodeConstants.Types.DUP_REMOVE) {
+		    		//TODO there's an analog here for a non-partitioned union, but it would mean checking projections from each branch
+		    		boolean allConstants = true;
+		    		for (Expression ex : outputElements) {
+		    			if (!(SymbolMap.getExpression(ex) instanceof Constant)) {
+		    				allConstants = false;
+		    				break;
+		    			}
+		    		}
+		    		if (allConstants && addLimit(rules, root, metadata, capFinder)) {
+		    			//TODO we could more gracefully handle the !addLimit case
+			    		PlanNode parent = root.getParent();
+			    		if (parent != null) {
+			    			NodeEditor.removeChildNode(root.getParent(), root);
+				    		execute(parent, metadata, capFinder, rules, analysisRecord, context);
+				    		return;
+			    		}
+		    		}
+		    	}
 		    case NodeConstants.Types.TUPLE_LIMIT:
-		    case NodeConstants.Types.DUP_REMOVE:
 		    case NodeConstants.Types.SORT:
 		    	if (root.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
 		    		//add missing sort columns
@@ -248,13 +267,8 @@
     					//just lob off everything under the projection
     					PlanNode project = NodeEditor.findNodePreOrder(parent, NodeConstants.Types.PROJECT);
     					project.removeAllChildren();
-    				} else {
-    					PlanNode limit = NodeFactory.getNewNode(NodeConstants.Types.TUPLE_LIMIT);
-        				limit.setProperty(Info.MAX_TUPLE_LIMIT, new Constant(1));
-	    				if (!rules.contains(RuleConstants.PUSH_LIMIT)) {
-	    					rules.push(RuleConstants.PUSH_LIMIT);
-	    				}
-						parent.getFirstChild().addAsParent(limit);
+    				} else if (!addLimit(rules, parent, metadata, capFinder)) {
+						throw new AssertionError("expected limit node to be added"); //$NON-NLS-1$
     				}
 	            	execute(parent, metadata, capFinder, rules, analysisRecord, context);
 	            	return;
@@ -277,6 +291,33 @@
 		}
 	}
 
+	private boolean addLimit(RuleStack rules, PlanNode parent, QueryMetadataInterface metadata, CapabilitiesFinder capabilitiesFinder) throws QueryMetadataException, TeiidComponentException {
+		PlanNode accessNode = NodeEditor.findParent(parent.getFirstChild(), NodeConstants.Types.ACCESS);
+		
+		if (accessNode != null) {
+			Object mid = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
+			if (!CapabilitiesUtil.supports(Capability.ROW_LIMIT, mid, metadata, capabilitiesFinder)) {
+				if (NodeEditor.findParent(parent, NodeConstants.Types.SET_OP | NodeConstants.Types.JOIN, NodeConstants.Types.ACCESS) != null) {
+					return false; //access node is too high
+				}
+				parent = accessNode.getParent();
+				if (parent == null) {
+					return false; //cannot modify the root - TODO could move this logic to another rule
+				}
+			}
+		}
+		
+		PlanNode limit = NodeFactory.getNewNode(NodeConstants.Types.TUPLE_LIMIT);
+		limit.setProperty(Info.MAX_TUPLE_LIMIT, new Constant(1));
+		
+		if (!rules.contains(RuleConstants.PUSH_LIMIT)) {
+			rules.push(RuleConstants.PUSH_LIMIT);
+		}
+		
+		parent.getFirstChild().addAsParent(limit);
+		return true;
+	}
+
 	static PlanNode removeGroupBy(PlanNode root,
 			QueryMetadataInterface metadata)
 			throws QueryPlannerException {

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -26,6 +26,7 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
@@ -35,10 +36,12 @@
 import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.metadata.QueryMetadataInterface;
 import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
 import org.teiid.query.optimizer.relational.OptimizerRule;
 import org.teiid.query.optimizer.relational.RuleStack;
 import org.teiid.query.optimizer.relational.plantree.NodeConstants;
 import org.teiid.query.optimizer.relational.plantree.NodeEditor;
+import org.teiid.query.optimizer.relational.plantree.NodeFactory;
 import org.teiid.query.optimizer.relational.plantree.PlanNode;
 import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
 import org.teiid.query.resolver.util.AccessPattern;
@@ -70,7 +73,7 @@
     	boolean beforeDecomposeJoin = rules.contains(RuleConstants.DECOMPOSE_JOIN);
         for (PlanNode sourceNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.SOURCE)) {
             if (sourceNode.getChildCount() > 0) {
-                plan = doMerge(sourceNode, plan, beforeDecomposeJoin, metadata);
+                plan = doMerge(sourceNode, plan, beforeDecomposeJoin, metadata, capFinder);
             }
         }
 
@@ -79,7 +82,7 @@
 
     static PlanNode doMerge(PlanNode frame,
                             PlanNode root, boolean beforeDecomposeJoin,
-                            QueryMetadataInterface metadata) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
+                            QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
     	if (frame.hasBooleanProperty(Info.NO_UNNEST)) {
     		return root;
     	}
@@ -154,7 +157,7 @@
             	return root; //don't bother to merge until after
             }
 
-            return checkForSimpleProjection(frame, root, parentProject, metadata);
+            return checkForSimpleProjection(frame, root, parentProject, metadata, capFinder);
         }
 
         PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE);
@@ -201,6 +204,7 @@
 
     /**
      * Removes source layers that only do a simple projection of the elements below.
+     * @param capFinder 
      * @throws TeiidComponentException 
      * @throws QueryMetadataException 
      * @throws QueryPlannerException 
@@ -208,7 +212,7 @@
     private static PlanNode checkForSimpleProjection(PlanNode frame,
                                                      PlanNode root,
                                                      PlanNode parentProject,
-                                                     QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
+                                                     QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
         // check that the parent only performs projection
         PlanNode nodeToCheck = parentProject.getFirstChild();
         while (nodeToCheck != frame) {
@@ -265,6 +269,7 @@
             PlanNode setOp = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE);
             if (setOp != null) {
                 setOp.setProperty(NodeConstants.Info.USE_ALL, Boolean.FALSE);
+                distributeDupRemove(metadata, capFinder, setOp);
                 if (parentProject.getParent().getParent() != null) {
                     NodeEditor.removeChildNode(parentProject.getParent().getParent(), parentProject.getParent());
                 } else {
@@ -395,6 +400,52 @@
         }
         return true;
     }
+    
+	static void distributeDupRemove(QueryMetadataInterface metadata,
+			CapabilitiesFinder capabilitiesFinder, PlanNode unionNode)
+			throws QueryMetadataException, TeiidComponentException {
+		PlanNode unionParentSource = NodeEditor.findParent(unionNode, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
+		if (unionNode.hasBooleanProperty(Info.USE_ALL) 
+				|| unionParentSource == null 
+				|| unionParentSource.getType() != NodeConstants.Types.SOURCE 
+				|| !unionParentSource.hasProperty(Info.PARTITION_INFO)) {
+			return;
+		}
+		
+		PlanNode accessNode = NodeEditor.findParent(unionNode, NodeConstants.Types.ACCESS);
+		if (accessNode != null) {
+			Object mid = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
+			if (!CapabilitiesUtil.supports(Capability.QUERY_SELECT_DISTINCT, mid, metadata, capabilitiesFinder)) {
+				return;
+			}
+		}
+		
+		//distribute dup remove
+		LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
+		RulePushAggregates.findUnionChildren(unionChildren, false, unionNode);
+		unionNode.setProperty(Info.USE_ALL, true);
+		for (PlanNode node : unionChildren) {
+			if (node.getType() == NodeConstants.Types.SET_OP) {
+				node.setProperty(Info.USE_ALL, false);
+			} else {
+				PlanNode projectNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.DUP_REMOVE | NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE);
+				if (projectNode != null && projectNode.getType() == NodeConstants.Types.PROJECT) {
+					accessNode = NodeEditor.findParent(projectNode, NodeConstants.Types.ACCESS);
+					PlanNode dup = NodeFactory.getNewNode(NodeConstants.Types.DUP_REMOVE);
+					if (accessNode == null) {
+						projectNode.addAsParent(dup);
+					} else {
+						Object mid = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
+						if (CapabilitiesUtil.supports(Capability.QUERY_SELECT_DISTINCT, mid, metadata, capabilitiesFinder)) {
+							projectNode.addAsParent(dup);
+						} else {
+							accessNode.addAsParent(dup);
+						}
+					}
+				}
+			}
+		}
+	}
 
     public String toString() {
         return "MergeVirtual"; //$NON-NLS-1$

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -386,7 +386,7 @@
 			}
 			//temporarily remove the access node
 			NodeEditor.removeChildNode(source, planNode);
-			PlanNode parent = RuleMergeVirtual.doMerge(source, source.getParent(), false, metadata);
+			PlanNode parent = RuleMergeVirtual.doMerge(source, source.getParent(), false, metadata, capFinder);
 			//add it back
 			if (parent.getFirstChild() == source) {
 				source.getFirstChild().addAsParent(planNode);

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushLimit.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -43,10 +43,10 @@
 import org.teiid.query.optimizer.relational.OptimizerRule;
 import org.teiid.query.optimizer.relational.RuleStack;
 import org.teiid.query.optimizer.relational.plantree.NodeConstants;
-import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
 import org.teiid.query.optimizer.relational.plantree.NodeEditor;
 import org.teiid.query.optimizer.relational.plantree.NodeFactory;
 import org.teiid.query.optimizer.relational.plantree.PlanNode;
+import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
 import org.teiid.query.sql.lang.CompareCriteria;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.SetQuery;
@@ -108,6 +108,8 @@
             
             while (canPushLimit(plan, limitNode, limitNodes, metadata, capabilitiesFinder, analysisRecord)) {
                 plan = RuleRaiseAccess.performRaise(plan, limitNode.getFirstChild(), limitNode);
+                //makes this rule safe to run after the final rule assign output elements
+                limitNode.setProperty(Info.OUTPUT_COLS, limitNode.getFirstChild().getProperty(Info.OUTPUT_COLS));
             }
             
             limitNodes.remove(limitNode);

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseNull.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseNull.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseNull.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -204,7 +204,7 @@
                 PlanNode sourceNode = NodeEditor.findParent(grandParent.getFirstChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SET_OP);
                                 
                 if (sourceNode != null) {
-                    return RuleMergeVirtual.doMerge(sourceNode, rootNode, false, metadata);
+                    return RuleMergeVirtual.doMerge(sourceNode, rootNode, false, metadata, capFinder);
                 }
                 return null;
             }

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -6631,6 +6631,52 @@
             });                                    
     }
     
+    @Test public void testDistinctConstant() throws Exception { 
+        String sql = "select distinct 1 from pm1.g1"; //$NON-NLS-1$
+
+        ProcessorPlan plan = helpPlan(sql, RealMetadataFactory.example1Cached(), null, getGenericFinder(), 
+                                      new String[] {"SELECT DISTINCT 1 FROM pm1.g1 AS g_0"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+        
+        checkNodeTypes(plan, FULL_PUSHDOWN);
+    }
+    
+    //TODO: there is an unnecessary dup removal here since it is the root and the optimization cannot modify the plan root
+    @Test public void testDistinctConstant1() throws Exception { 
+        String sql = "select distinct 1 from pm1.g1"; //$NON-NLS-1$
+
+        ProcessorPlan plan = helpPlan(sql, RealMetadataFactory.example1Cached(), null, new DefaultCapabilitiesFinder(), 
+                                      new String[] {"SELECT pm1.g1.e1 FROM pm1.g1"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+        
+        checkNodeTypes(plan, new int[] {
+                1,      // Access
+                0,      // DependentAccess
+                0,      // DependentSelect
+                0,      // DependentProject
+                1,      // DupRemove
+                0,      // Grouping
+                1,		// Limit
+                0,      // NestedLoopJoinStrategy
+                0,      // MergeJoinStrategy
+                0,      // Null
+                0,      // PlanExecution
+                1,      // Project
+                0,      // Select
+                0,      // Sort
+                0       // UnionAll
+            }, TestLimit.NODE_TYPES);          
+    }
+    
+    @Test public void testDistinctConstant2() throws Exception { 
+        String sql = "select distinct 1 from pm1.g1"; //$NON-NLS-1$
+        BasicSourceCapabilities bsc = getTypicalCapabilities();
+        bsc.setCapabilitySupport(Capability.ROW_LIMIT, true);
+        CapabilitiesFinder capFinder = new DefaultCapabilitiesFinder(bsc);
+        ProcessorPlan plan = helpPlan(sql, RealMetadataFactory.example1Cached(), null, capFinder, 
+                                      new String[] {"SELECT 1 AS c_0 FROM pm1.g1 AS g_0 LIMIT 1"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+        
+        checkNodeTypes(plan, FULL_PUSHDOWN);
+    }
+    
 	public static final boolean DEBUG = false;
 
 }

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestUnionPlanning.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestUnionPlanning.java	2012-04-26 19:09:46 UTC (rev 4037)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestUnionPlanning.java	2012-04-26 19:58:31 UTC (rev 4038)
@@ -333,5 +333,27 @@
             2       // UnionAll
         });                                    
     }   
+    
+    @Test public void testUnionPartitionedDistinct() throws Exception {
+        ProcessorPlan plan = TestOptimizer.helpPlan("select distinct * from (SELECT 1 as IntKey, intnum FROM BQT1.SmallA UNION ALL SELECT 2 as intkey, intnum FROM BQT2.SmallA) A", RealMetadataFactory.exampleBQTCached(), null, TestInlineView.getInliveViewCapabilitiesFinder(),//$NON-NLS-1$
+            new String[] { "SELECT DISTINCT g_0.intnum FROM BQT2.SmallA AS g_0", "SELECT DISTINCT g_0.intnum FROM BQT1.SmallA AS g_0" }, ComparisonMode.EXACT_COMMAND_STRING); 
 
+        TestOptimizer.checkNodeTypes(plan, new int[] {
+            2,      // Access
+            0,      // DependentAccess
+            0,      // DependentSelect
+            0,      // DependentProject
+            0,      // DupRemove
+            0,      // Grouping
+            0,      // NestedLoopJoinStrategy
+            0,      // MergeJoinStrategy
+            0,      // Null
+            0,      // PlanExecution
+            0,      // Project
+            0,      // Select
+            0,      // Sort
+            1       // UnionAll
+        });                                    
+    }  
+
 }



More information about the teiid-commits mailing list