[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