[teiid-commits] teiid SVN: r2597 - in branches/7.1.x: engine/src/main/java/org/teiid/query/optimizer/relational/plantree and 2 other directories.
teiid-commits at lists.jboss.org
teiid-commits at lists.jboss.org
Wed Sep 22 17:14:19 EDT 2010
Author: shawkins
Date: 2010-09-22 17:14:19 -0400 (Wed, 22 Sep 2010)
New Revision: 2597
Modified:
branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java
branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java
branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
Log:
TEIID-1271 adding some logging for common pushdown decisions. there are still plenty more to add. TEIID-1272 making join ordering decisions use a better heuristic when 1 side is unknown
Modified: branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml
===================================================================
--- branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/documentation/developer-guide/src/main/docbook/en-US/content/translator-api.xml 2010-09-22 21:14:19 UTC (rev 2597)
@@ -680,10 +680,10 @@
<title>Translator Capabilities</title>
<para>The <code>ExecutionFactory</code> class defines all the methods that describe the capabilities of a Translator.
These are used by the Connector Manager to determine what kinds of commands the translator is
- capable of executing. A base <code>ExecutionFactory</code> class implements all the basic capabilities, which says
- your translator does not support any cpabilities. Your extended
+ capable of executing. A base <code>ExecutionFactory</code> class implements all the basic capabilities methods, which says
+ your translator does not support any capabilities. Your extended
<code>ExecutionFactory</code> class must override the the necessary methods to specify which
- capabilities your translator supports. </para>
+ capabilities your translator supports. You should consult the debug log of query planning (set showplan debug) to see if desired pushdown requires additional capabilities.</para>
<section>
<title>Capability Scope</title>
<para>
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -378,5 +378,13 @@
}
return ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(toSearch);
}
+
+ public float getCardinality() {
+ Float cardinality = (Float) this.getProperty(NodeConstants.Info.EST_CARDINALITY);
+ if (cardinality == null) {
+ return -1f;
+ }
+ return cardinality;
+ }
}
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -28,6 +28,7 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.core.TeiidComponentException;
import org.teiid.query.QueryPlugin;
+import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.function.metadata.FunctionMethod;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.SupportConstants;
@@ -83,6 +84,7 @@
private Object modelID;
private QueryMetadataInterface metadata;
private CapabilitiesFinder capFinder;
+ private AnalysisRecord analysisRecord;
// Retrieved during initialization and cached
private SourceCapabilities caps;
@@ -105,48 +107,48 @@
@Override
public void visit(XMLAttributes obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLAttributes not allowed"); //$NON-NLS-1$
}
@Override
public void visit(XMLNamespaces obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLNamespaces not allowed"); //$NON-NLS-1$
}
@Override
public void visit(XMLForest obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLForest not allowed"); //$NON-NLS-1$
}
@Override
public void visit(XMLElement obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLElement not allowed"); //$NON-NLS-1$
}
@Override
public void visit(XMLSerialize obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLSerialize not allowed"); //$NON-NLS-1$
}
@Override
public void visit(XMLParse obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLParse not allowed"); //$NON-NLS-1$
}
@Override
public void visit(XMLQuery obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of XMLQuery not allowed"); //$NON-NLS-1$
}
@Override
public void visit(QueryString obj) {
- markInvalid();
+ markInvalid(obj, "Pushdown of QueryString not allowed"); //$NON-NLS-1$
}
public void visit(AggregateSymbol obj) {
try {
if(! CapabilitiesUtil.supportsAggregateFunction(modelID, obj, metadata, capFinder)) {
- markInvalid();
+ markInvalid(obj, "Aggregate function pushdown not supported by source"); //$NON-NLS-1$
}
} catch(QueryMetadataException e) {
handleException(new TeiidComponentException(e));
@@ -157,7 +159,7 @@
public void visit(CaseExpression obj) {
if(! this.caps.supportsCapability(Capability.QUERY_CASE)) {
- markInvalid();
+ markInvalid(obj, "CaseExpression pushdown not supported by source"); //$NON-NLS-1$
}
}
@@ -186,10 +188,12 @@
// Check if compares are allowed
if(! this.caps.supportsCapability(operatorCap)) {
- markInvalid();
+ markInvalid(obj, "ordered CompareCriteria not supported by source"); //$NON-NLS-1$
+ return;
}
if (negated && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
- markInvalid();
+ markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
+ return;
}
// Check capabilities of the elements
@@ -206,12 +210,8 @@
int operator = crit.getOperator();
// Verify capabilities are supported
- if(operator == CompoundCriteria.OR) {
- // Check if OR is allowed
- if(! this.caps.supportsCapability(Capability.CRITERIA_OR)) {
- markInvalid();
- return;
- }
+ if(operator == CompoundCriteria.OR && !this.caps.supportsCapability(Capability.CRITERIA_OR)) {
+ markInvalid(crit, "OR criteria not supported by source"); //$NON-NLS-1$
}
}
@@ -221,9 +221,13 @@
if (EvaluatableVisitor.willBecomeConstant(obj, true)) {
return;
}
- if(obj.getFunctionDescriptor().getPushdown() == FunctionMethod.CANNOT_PUSHDOWN || ! CapabilitiesUtil.supportsScalarFunction(modelID, obj, metadata, capFinder)) {
- markInvalid();
+ if(obj.getFunctionDescriptor().getPushdown() == FunctionMethod.CANNOT_PUSHDOWN) {
+ markInvalid(obj, "Function metadata indicates it cannot be pusheddown."); //$NON-NLS-1$
+ return;
}
+ if (! CapabilitiesUtil.supportsScalarFunction(modelID, obj, metadata, capFinder)) {
+ markInvalid(obj, obj.isImplicit()?"":"(implicit) convert" + " Function not supported by source"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
} catch(QueryMetadataException e) {
handleException(new TeiidComponentException(e));
} catch(TeiidComponentException e) {
@@ -234,12 +238,12 @@
public void visit(IsNullCriteria obj) {
// Check if compares are allowed
if(! this.caps.supportsCapability(Capability.CRITERIA_ISNULL)) {
- markInvalid();
+ markInvalid(obj, "IsNull not supported by source"); //$NON-NLS-1$
return;
}
if (obj.isNegated() && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
- markInvalid();
+ markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
return;
}
}
@@ -247,21 +251,21 @@
public void visit(MatchCriteria obj) {
// Check if compares are allowed
if(! this.caps.supportsCapability(Capability.CRITERIA_LIKE)) {
- markInvalid();
+ markInvalid(obj, "Like is not supported by source"); //$NON-NLS-1$
return;
}
// Check ESCAPE char if necessary
if(obj.getEscapeChar() != MatchCriteria.NULL_ESCAPE_CHAR) {
if(! this.caps.supportsCapability(Capability.CRITERIA_LIKE_ESCAPE)) {
- markInvalid();
+ markInvalid(obj, "Like escape is not supported by source"); //$NON-NLS-1$
return;
}
}
//check NOT
if(obj.isNegated() && ! this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
- markInvalid();
+ markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
return;
}
@@ -278,18 +282,14 @@
public void visit(NotCriteria obj) {
// Check if compares are allowed
if(! this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
- markInvalid();
+ markInvalid(obj, "Negation is not supported by source"); //$NON-NLS-1$
return;
}
}
public void visit(SearchedCaseExpression obj) {
- if (this.caps == null) {
- return;
- }
-
if(! this.caps.supportsCapability(Capability.QUERY_SEARCHED_CASE)) {
- markInvalid();
+ markInvalid(obj, "SearchedCase is not supported by source"); //$NON-NLS-1$
}
}
@@ -299,7 +299,7 @@
int maxSize = CapabilitiesUtil.getMaxInCriteriaSize(modelID, metadata, capFinder);
if (maxSize > 0 && crit.getValues().size() > maxSize) {
- markInvalid();
+ markInvalid(crit, "SetCriteria size exceeds maximum for source"); //$NON-NLS-1$
return;
}
} catch(QueryMetadataException e) {
@@ -315,13 +315,13 @@
public void visit(ExistsCriteria crit) {
// Check if exists criteria are allowed
if(! this.caps.supportsCapability(Capability.CRITERIA_EXISTS)) {
- markInvalid();
+ markInvalid(crit, "Exists is not supported by source"); //$NON-NLS-1$
return;
}
try {
- if (validateSubqueryPushdown(crit, modelID, metadata, capFinder) == null) {
- markInvalid();
+ if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
+ markInvalid(crit.getCommand(), "Subquery cannot be pushed down"); //$NON-NLS-1$
}
} catch (TeiidComponentException e) {
handleException(e);
@@ -346,7 +346,7 @@
break;
}
if(! this.caps.supportsCapability(capability)) {
- markInvalid();
+ markInvalid(crit, "SubqueryCompare not supported by source"); //$NON-NLS-1$
return;
}
@@ -354,8 +354,8 @@
// Check capabilities of the elements
try {
- if (validateSubqueryPushdown(crit, modelID, metadata, capFinder) == null) {
- markInvalid();
+ if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
+ markInvalid(crit.getCommand(), "Subquery cannot be pushed down"); //$NON-NLS-1$
}
} catch(QueryMetadataException e) {
handleException(new TeiidComponentException(e));
@@ -368,11 +368,12 @@
public void visit(ScalarSubquery obj) {
try {
if(!this.caps.supportsCapability(Capability.QUERY_SUBQUERIES_SCALAR)
- || validateSubqueryPushdown(obj, modelID, metadata, capFinder) == null) {
+ || validateSubqueryPushdown(obj, modelID, metadata, capFinder, analysisRecord) == null) {
if (obj.getCommand().getCorrelatedReferences() == null) {
obj.setShouldEvaluate(true);
} else {
- markInvalid();
+ markInvalid(obj.getCommand(), !this.caps.supportsCapability(Capability.QUERY_SUBQUERIES_SCALAR)?
+ "Correlated ScalarSubquery is not supported":"Subquery cannot be pushed down"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
} catch(QueryMetadataException e) {
@@ -387,12 +388,12 @@
try {
// Check if compares with subqueries are allowed
if(! this.caps.supportsCapability(Capability.CRITERIA_IN_SUBQUERY)) {
- markInvalid();
+ markInvalid(crit, "SubqueryIn is not supported by source"); //$NON-NLS-1$
return;
}
- if (validateSubqueryPushdown(crit, modelID, metadata, capFinder) == null) {
- markInvalid();
+ if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
+ markInvalid(crit.getCommand(), "Subquery cannot be pushed down"); //$NON-NLS-1$
}
} catch(QueryMetadataException e) {
handleException(new TeiidComponentException(e));
@@ -405,12 +406,12 @@
try {
// Check if compares are allowed
if(! this.caps.supportsCapability(Capability.CRITERIA_IN)) {
- markInvalid();
+ markInvalid(crit, "In is not supported by source"); //$NON-NLS-1$
return;
}
if (crit.isNegated() && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
- markInvalid();
+ markInvalid(crit, "Negation is not supported by source"); //$NON-NLS-1$
return;
}
// Check capabilities of the elements
@@ -431,7 +432,7 @@
private void checkElementsAreSearchable(LanguageObject crit, int searchableType)
throws QueryMetadataException, TeiidComponentException {
if (!CapabilitiesUtil.checkElementsAreSearchable(Arrays.asList(crit), metadata, searchableType)) {
- markInvalid();
+ markInvalid(crit, "not all source columns support search type"); //$NON-NLS-1$
}
}
@@ -445,7 +446,7 @@
* @return
* @throws TeiidComponentException
*/
- static Object validateSubqueryPushdown(SubqueryContainer subqueryContainer, Object critNodeModelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws TeiidComponentException {
+ static Object validateSubqueryPushdown(SubqueryContainer subqueryContainer, Object critNodeModelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord) throws TeiidComponentException {
ProcessorPlan plan = subqueryContainer.getCommand().getProcessorPlan();
if (plan != null) {
if(!(plan instanceof RelationalPlan)) {
@@ -497,7 +498,7 @@
}
//TODO: this check sees as correlated references as coming from the containing scope
//but this is only an issue with deeply nested subqueries
- if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(subqueryContainer.getCommand(), critNodeModelID, metadata, capFinder)) {
+ if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(subqueryContainer.getCommand(), critNodeModelID, metadata, capFinder, analysisRecord )) {
return null;
}
}
@@ -519,16 +520,19 @@
return this.exception;
}
- private void markInvalid() {
+ private void markInvalid(LanguageObject object, String reason) {
this.valid = false;
setAbort(true);
+ if (analysisRecord != null && analysisRecord.recordDebug()) {
+ analysisRecord.println(reason + " " + object); //$NON-NLS-1$
+ }
}
public boolean isValid() {
return this.valid;
}
- public static boolean canPushLanguageObject(LanguageObject obj, Object modelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
+ public static boolean canPushLanguageObject(LanguageObject obj, Object modelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException {
if(obj == null) {
return true;
}
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -42,6 +42,7 @@
import org.teiid.query.optimizer.relational.plantree.PlanNode;
import org.teiid.query.resolver.util.AccessPattern;
import org.teiid.query.sql.lang.CompareCriteria;
+import org.teiid.query.sql.lang.CompoundCriteria;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
@@ -233,8 +234,10 @@
* @param joinOrder
* @param metadata
* @return
+ * @throws TeiidComponentException
+ * @throws QueryMetadataException
*/
- public double scoreRegion(Object[] joinOrder, QueryMetadataInterface metadata) {
+ public double scoreRegion(Object[] joinOrder, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
List<Map.Entry<PlanNode, PlanNode>> joinSourceEntries = new ArrayList<Map.Entry<PlanNode, PlanNode>>(joinSourceNodes.entrySet());
double totalIntermediatCost = 0;
double cost = 1;
@@ -263,17 +266,35 @@
float sourceCost = ((Float)joinSourceRoot.getProperty(NodeConstants.Info.EST_CARDINALITY)).floatValue();
- if (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
- sourceCost = UNKNOWN_TUPLE_EST;
+ List<PlanNode> applicableCriteria = null;
+
+ if (!criteria.isEmpty() && i > 0) {
+ applicableCriteria = getJoinCriteriaForGroups(groups, criteria);
+ }
+
+ if (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
+ sourceCost = UNKNOWN_TUPLE_EST;
+ if (applicableCriteria != null && !applicableCriteria.isEmpty()) {
+ CompoundCriteria cc = new CompoundCriteria();
+ for (PlanNode planNode : applicableCriteria) {
+ cc.addCriteria((Criteria) planNode.getProperty(NodeConstants.Info.SELECT_CRITERIA));
+ }
+ sourceCost = (float)cost;
+ criteria.removeAll(applicableCriteria);
+ applicableCriteria = null;
+ if (NewCalculateCostUtil.usesKey(cc, metadata)) {
+ sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING, sourceCost));
+ } else {
+ sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING * 2, sourceCost));
+ }
+ }
} else if (Double.isInfinite(sourceCost) || Double.isNaN(sourceCost)) {
- sourceCost = UNKNOWN_TUPLE_EST * 10;
+ return Double.MAX_VALUE;
}
-
+
cost *= sourceCost;
- if (!criteria.isEmpty() && i > 0) {
- List<PlanNode> applicableCriteria = getJoinCriteriaForGroups(groups, criteria);
-
+ if (applicableCriteria != null) {
for (PlanNode criteriaNode : applicableCriteria) {
float filter = ((Float)criteriaNode.getProperty(NodeConstants.Info.EST_SELECTIVITY)).floatValue();
@@ -282,7 +303,6 @@
criteria.removeAll(applicableCriteria);
}
-
totalIntermediatCost += cost;
}
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -76,7 +76,8 @@
*/
public class NewCalculateCostUtil {
- public static final float UNKNOWN_VALUE = -1;
+ public static final int UNKNOWN_JOIN_SCALING = 20;
+ public static final float UNKNOWN_VALUE = -1;
// the following variables are used to hold cost estimates (roughly in milliseconds)
private final static float compareTime = .05f; //TODO: a better estimate would be based upon the number of conjuncts
@@ -181,13 +182,13 @@
case NodeConstants.Types.TUPLE_LIMIT:
{
PlanNode child = node.getFirstChild();
- Float childCost = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
+ float childCost = child.getCardinality();
Expression offset = (Expression)node.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
Float cost = childCost;
- if (childCost.floatValue() != UNKNOWN_VALUE && offset instanceof Constant) {
- float offsetCost = childCost.floatValue() - ((Number)((Constant)offset).getValue()).floatValue();
+ if (childCost != UNKNOWN_VALUE && offset instanceof Constant) {
+ float offsetCost = childCost - ((Number)((Constant)offset).getValue()).floatValue();
cost = new Float((offsetCost < 0) ? 0 : offsetCost);
}
@@ -277,39 +278,43 @@
private static void estimateJoinNodeCost(PlanNode node, QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException {
- Iterator children = node.getChildren().iterator();
- PlanNode child1 = (PlanNode)children.next();
- Float childCost1 = (Float)child1.getProperty(NodeConstants.Info.EST_CARDINALITY);
- PlanNode child2 = (PlanNode)children.next();
- Float childCost2 = (Float)child2.getProperty(NodeConstants.Info.EST_CARDINALITY);
- if (childCost1 != null && childCost2 != null && childCost1.floatValue() != UNKNOWN_VALUE && childCost2.floatValue() != UNKNOWN_VALUE){
+ Iterator<PlanNode> children = node.getChildren().iterator();
+ PlanNode child1 = children.next();
+ float childCost1 = child1.getCardinality();
+ PlanNode child2 = children.next();
+ float childCost2 = child2.getCardinality();
+
+ if (childCost1 == UNKNOWN_VALUE || childCost2 == UNKNOWN_VALUE) {
+ setCardinalityEstimate(node, null);
+ return;
+ }
- JoinType joinType = (JoinType)node.getProperty(NodeConstants.Info.JOIN_TYPE);
- List joinCriteria = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
-
- float baseCost = childCost1.floatValue() * childCost2.floatValue();
- if (joinCriteria != null && !joinCriteria.isEmpty()) {
- Criteria crit = Criteria.combineCriteria(joinCriteria);
- baseCost = recursiveEstimateCostOfCriteria(baseCost, node, crit, metadata);
- }
-
- Float cost = null;
- if (JoinType.JOIN_CROSS.equals(joinType)){
- cost = new Float(baseCost);
- } else if (JoinType.JOIN_FULL_OUTER.equals(joinType)) {
- cost = new Float(Math.max((childCost1.floatValue()+childCost2.floatValue()),baseCost));
- } else if (JoinType.JOIN_LEFT_OUTER.equals(joinType)) {
- cost = new Float(Math.max(childCost1.floatValue(),baseCost));
- } else if (JoinType.JOIN_RIGHT_OUTER.equals(joinType)) {
- cost = new Float(Math.max(childCost2.floatValue(),baseCost));
- } else if (JoinType.JOIN_INNER.equals(joinType)) {
- cost = new Float(baseCost);
- }
-
- setCardinalityEstimate(node, cost);
- } else {
- setCardinalityEstimate(node, null);
+ JoinType joinType = (JoinType)node.getProperty(NodeConstants.Info.JOIN_TYPE);
+ List joinCriteria = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
+
+ float baseCost = childCost1 * childCost2;
+
+ if (joinCriteria != null && !joinCriteria.isEmpty()) {
+ Criteria crit = Criteria.combineCriteria(joinCriteria);
+ //TODO: we may be able to get a fairly accurate join estimate if the
+ //unknown side is being joined with a key
+ baseCost = recursiveEstimateCostOfCriteria(baseCost, node, crit, metadata);
}
+
+ Float cost = null;
+ if (JoinType.JOIN_CROSS.equals(joinType)){
+ cost = new Float(baseCost);
+ } else if (JoinType.JOIN_FULL_OUTER.equals(joinType)) {
+ cost = new Float(Math.max((childCost1+childCost2),baseCost));
+ } else if (JoinType.JOIN_LEFT_OUTER.equals(joinType)) {
+ cost = new Float(Math.max(childCost1,baseCost));
+ } else if (JoinType.JOIN_RIGHT_OUTER.equals(joinType)) {
+ cost = new Float(Math.max(childCost2,baseCost));
+ } else if (JoinType.JOIN_INNER.equals(joinType)) {
+ cost = new Float(baseCost);
+ }
+
+ setCardinalityEstimate(node, cost);
}
/**
@@ -321,11 +326,7 @@
throws QueryMetadataException, TeiidComponentException {
PlanNode child = node.getFirstChild();
- Float childCostFloat = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
- float childCost = UNKNOWN_VALUE;
- if (childCostFloat != null){
- childCost = childCostFloat.floatValue();
- }
+ float childCost = child.getCardinality();
//Get list of conjuncts
Criteria selectCriteria = (Criteria)node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
@@ -350,10 +351,7 @@
//only cost non-correlated TODO: a better estimate for correlated
if (references == null) {
PlanNode child = node.getFirstChild();
- Float childCostFloat = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
- if (childCostFloat != null) {
- cost = childCostFloat.floatValue();
- }
+ cost = child.getCardinality();
}
}else {
GroupSymbol group = node.getGroups().iterator().next();
@@ -379,7 +377,7 @@
throws QueryMetadataException, TeiidComponentException {
PlanNode child = node.getFirstChild();
- float childCost = ((Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY)).floatValue();
+ float childCost = child.getCardinality();
if(childCost == UNKNOWN_VALUE) {
setCardinalityEstimate(node, null);
@@ -421,12 +419,9 @@
if (compCrit.getOperator() == CompoundCriteria.OR) {
cost = 0;
}
- HashSet<ElementSymbol> elements = new HashSet<ElementSymbol>();
- collectElementsOfValidCriteria(compCrit, elements);
- if (usesKey(elements, metadata)) {
+ if (usesKey(compCrit, metadata)) {
return 1;
}
-
for (Criteria critPart : compCrit.getCriteria()) {
float nextCost = recursiveEstimateCostOfCriteria(childCost, currentNode, critPart, metadata);
@@ -497,7 +492,7 @@
if(criteria instanceof CompoundCriteria) {
CompoundCriteria compCrit = (CompoundCriteria) criteria;
- Iterator iter = compCrit.getCriteria().iterator();
+ Iterator<Criteria> iter = compCrit.getCriteria().iterator();
boolean first = true;
Collection<ElementSymbol> savedElements = elements;
if(compCrit.getOperator() == CompoundCriteria.OR) {
@@ -505,11 +500,11 @@
}
while(iter.hasNext()) {
if(compCrit.getOperator() == CompoundCriteria.AND || first) {
- collectElementsOfValidCriteria((Criteria) iter.next(), elements);
+ collectElementsOfValidCriteria(iter.next(), elements);
first = false;
} else {
HashSet<ElementSymbol> other = new HashSet<ElementSymbol>();
- collectElementsOfValidCriteria((Criteria) iter.next(), other);
+ collectElementsOfValidCriteria(iter.next(), other);
elements.retainAll(other);
}
}
@@ -532,7 +527,6 @@
if (!setCriteria.isNegated()) {
ElementCollectorVisitor.getElements(setCriteria.getExpression(), elements);
}
-
} else if(criteria instanceof IsNullCriteria) {
IsNullCriteria isNullCriteria = (IsNullCriteria)criteria;
if (!isNullCriteria.isNegated()) {
@@ -769,6 +763,12 @@
&& usesKey(allElements, metadata);
}
+ public static boolean usesKey(Criteria crit, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ HashSet<ElementSymbol> elements = new HashSet<ElementSymbol>();
+ collectElementsOfValidCriteria(crit, elements);
+ return usesKey(elements, metadata);
+ }
+
/**
* TODO: this uses key check is not really accurate, it doesn't take into consideration where
* we are in the plan.
@@ -849,8 +849,8 @@
}
} else if (cardinality != UNKNOWN_VALUE) {
int groupCardinality = metadata.getCardinality(elementSymbol.getGroupSymbol().getMetadataID());
- if (groupCardinality != UNKNOWN_VALUE) {
- ndv *= cardinality / Math.max(1, groupCardinality);
+ if (groupCardinality != UNKNOWN_VALUE && groupCardinality > cardinality) {
+ ndv *= cardinality / Math.max(1, groupCardinality);
}
}
result = Math.max(result, ndv);
@@ -948,7 +948,7 @@
/**
* Computes the cost of a Dependent Join
*
- * The worst possible cost will arise from a high independent ndv (many dependent sets) and a low depenendent ndv (possibly many matches per set)
+ * The worst possible cost will arise from a high independent ndv (many dependent sets) and a low dependent ndv (possibly many matches per set)
*
* This logic uses the same assumption as criteria in that ndv is used as a divisor of cardinality.
*
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -150,7 +150,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)) {
+ if (attemptPush && RuleRaiseAccess.canRaiseOverSort(sourceNode, metadata, capFinder, sortNode, null)) {
sourceNode.getFirstChild().addAsParent(sortNode);
if (needsCorrection) {
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -237,7 +237,7 @@
* Ideally we should be a little smarter in case 2
* - pushing down a same source cross join can be done if we know that a dependent join will be performed
*/
- boolean hasJoinCriteria = false;
+ //boolean hasJoinCriteria = false;
LinkedList<Criteria> joinCriteria = new LinkedList<Criteria>();
Object modelId = RuleRaiseAccess.getModelIDFromAccess(accessNode1, metadata);
SupportedJoinCriteria sjc = CapabilitiesUtil.getSupportedJoinCriteria(modelId, metadata, capFinder);
@@ -250,25 +250,27 @@
if (sources.contains(accessNode1)) {
if (sources.contains(accessNode2) && sources.size() == 2) {
- hasJoinCriteria = true;
+ //hasJoinCriteria = true;
Criteria crit = (Criteria)critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
- if (RuleRaiseAccess.isSupportedJoinCriteria(sjc, crit, modelId, metadata, capFinder)) {
+ if (RuleRaiseAccess.isSupportedJoinCriteria(sjc, crit, modelId, metadata, capFinder, null)) {
joinCriteriaNodes.add(critNode);
joinCriteria.add(crit);
}
} else if (!accessNodes.containsAll(sources)) {
- hasJoinCriteria = true;
+ //hasJoinCriteria = true;
}
} else if (sources.contains(accessNode2) && !accessNodes.containsAll(sources)) {
- hasJoinCriteria = true;
+ //hasJoinCriteria = true;
}
}
/*
- * If we failed to find direct criteria, but still have non-pushable or criteria to
- * other groups we'll use additional checks
+ * If we failed to find direct criteria, a cross join may still be acceptable
*/
- if ((!hasJoinCriteria || joinCriteriaNodes.isEmpty()) && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
+ if (joinCriteriaNodes.isEmpty() && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
+ //if (hasJoinCriteria) {
+ //a cross join would still be a good idea given that a dependent join can be used
+ //}
continue;
}
@@ -277,7 +279,7 @@
JoinType joinType = joinCriteria.isEmpty()?JoinType.JOIN_CROSS:JoinType.JOIN_INNER;
//try to push to the source
- if (RuleRaiseAccess.canRaiseOverJoin(toTest, metadata, capFinder, joinCriteria, joinType) == null) {
+ if (RuleRaiseAccess.canRaiseOverJoin(toTest, metadata, capFinder, joinCriteria, joinType, null) == null) {
continue;
}
@@ -521,7 +523,7 @@
* @param metadata
* @return
*/
- Object[] findBestJoinOrder(JoinRegion region, QueryMetadataInterface metadata) {
+ Object[] findBestJoinOrder(JoinRegion region, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
int regionCount = region.getJoinSourceNodes().size();
List<Integer> orderList = new ArrayList<Integer>(regionCount);
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -386,7 +386,7 @@
projectPlanNode.setProperty(NodeConstants.Info.PROJECT_COLS, projectedViewSymbols);
projectPlanNode.addGroup(group);
if (pushdown) {
- while (RuleRaiseAccess.raiseAccessNode(root, originalNode, metadata, capFinder, true) != null) {
+ while (RuleRaiseAccess.raiseAccessNode(root, originalNode, metadata, capFinder, true, null) != null) {
//continue to raise
}
}
@@ -487,7 +487,7 @@
//check for push down
if (stageGroup.getFirstChild().getType() == NodeConstants.Types.ACCESS
- && RuleRaiseAccess.canRaiseOverGroupBy(stageGroup, stageGroup.getFirstChild(), aggregates, metadata, capFinder)) {
+ && RuleRaiseAccess.canRaiseOverGroupBy(stageGroup, stageGroup.getFirstChild(), aggregates, metadata, capFinder, null)) {
RuleRaiseAccess.performRaise(null, stageGroup.getFirstChild(), stageGroup);
if (stagedGroupingSymbols.isEmpty()) {
RuleRaiseAccess.performRaise(null, stageGroup.getParent(), stageGroup.getParent().getParent());
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -94,7 +94,7 @@
continue;
}
- PlanNode sourceNode = findOriginatingNode(metadata, capFinder, critNode);
+ PlanNode sourceNode = findOriginatingNode(metadata, capFinder, critNode, analysisRecord);
if(sourceNode == null) {
deadNodes.add(critNode);
@@ -137,7 +137,7 @@
}
private PlanNode findOriginatingNode(QueryMetadataInterface metadata,
- CapabilitiesFinder capFinder, PlanNode critNode)
+ CapabilitiesFinder capFinder, PlanNode critNode, AnalysisRecord record)
throws TeiidComponentException, QueryMetadataException {
if (critNode.getGroups().isEmpty()) {
//check to see if pushing may impact cardinality
@@ -146,7 +146,7 @@
return groupNode;
}
- Object modelId = getSubqueryModelId(metadata, capFinder, critNode);
+ Object modelId = getSubqueryModelId(metadata, capFinder, critNode, record);
if (modelId != null) {
for (PlanNode node : NodeEditor.findAllNodes(critNode, NodeConstants.Types.SOURCE)) {
GroupSymbol group = node.getGroups().iterator().next();
@@ -161,11 +161,11 @@
}
private Object getSubqueryModelId(QueryMetadataInterface metadata,
- CapabilitiesFinder capFinder, PlanNode critNode)
+ CapabilitiesFinder capFinder, PlanNode critNode, AnalysisRecord record)
throws TeiidComponentException, QueryMetadataException {
Object modelId = null;
for (SubqueryContainer subqueryContainer : critNode.getSubqueryContainers()) {
- Object validId = CriteriaCapabilityValidatorVisitor.validateSubqueryPushdown(subqueryContainer, null, metadata, capFinder);
+ Object validId = CriteriaCapabilityValidatorVisitor.validateSubqueryPushdown(subqueryContainer, null, metadata, capFinder, record);
if (validId == null) {
return null;
}
@@ -282,7 +282,7 @@
// Look for situations where we don't allow SELECT to be pushed
if(currentNode.getType() == NodeConstants.Types.ACCESS) {
try {
- if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode)) {
+ if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode, null)) {
return currentNode;
}
Modified: branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRaiseAccess.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -73,7 +73,7 @@
raisedNode = false;
for (PlanNode accessNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.ACCESS)) {
- PlanNode newRoot = raiseAccessNode(plan, accessNode, metadata, capFinder, afterJoinPlanning);
+ PlanNode newRoot = raiseAccessNode(plan, accessNode, metadata, capFinder, afterJoinPlanning, analysisRecord);
if(newRoot != null) {
raisedNode = true;
plan = newRoot;
@@ -87,7 +87,8 @@
/**
* @return null if nothing changed, and a new plan root if something changed
*/
- static PlanNode raiseAccessNode(PlanNode rootNode, PlanNode accessNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, boolean afterJoinPlanning)
+ static PlanNode raiseAccessNode(PlanNode rootNode, PlanNode accessNode, QueryMetadataInterface metadata,
+ CapabilitiesFinder capFinder, boolean afterJoinPlanning, AnalysisRecord record)
throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
PlanNode parentNode = accessNode.getParent();
@@ -103,7 +104,7 @@
switch(parentNode.getType()) {
case NodeConstants.Types.JOIN:
{
- modelID = canRaiseOverJoin(modelID, parentNode, metadata, capFinder, afterJoinPlanning);
+ modelID = canRaiseOverJoin(modelID, parentNode, metadata, capFinder, afterJoinPlanning, record);
if(modelID != null) {
raiseAccessOverJoin(parentNode, modelID, true);
return rootNode;
@@ -117,7 +118,7 @@
for (int i = 0; i < projectCols.size(); i++) {
SingleElementSymbol symbol = (SingleElementSymbol)projectCols.get(i);
- if(! canPushSymbol(symbol, true, modelID, metadata, capFinder)) {
+ if(! canPushSymbol(symbol, true, modelID, metadata, capFinder, record)) {
return null;
}
}
@@ -138,10 +139,13 @@
{
// If model supports the support constant parameter, then move access node
if(!CapabilitiesUtil.supportsSelectDistinct(modelID, metadata, capFinder)) {
+ recordDebug("cannot push dupremove, since distinct is not supported by source", parentNode, record); //$NON-NLS-1$
return null;
}
+ //TODO: this check is too specific the columns could be used in expressions that are comparable
if (!CapabilitiesUtil.checkElementsAreSearchable((List)NodeEditor.findNodePreOrder(parentNode, NodeConstants.Types.PROJECT).getProperty(NodeConstants.Info.PROJECT_COLS), metadata, SupportConstants.Element.SEARCHABLE_COMPARE)) {
+ recordDebug("cannot push dupremove, since not all columns are comparable at the source", parentNode, record); //$NON-NLS-1$
return null;
}
@@ -149,7 +153,7 @@
}
case NodeConstants.Types.SORT:
{
- if (canRaiseOverSort(accessNode, metadata, capFinder, parentNode)) {
+ if (canRaiseOverSort(accessNode, metadata, capFinder, parentNode, record)) {
return performRaise(rootNode, accessNode, parentNode);
}
return null;
@@ -157,7 +161,7 @@
case NodeConstants.Types.GROUP:
{
Set<AggregateSymbol> aggregates = RulePushAggregates.collectAggregates(parentNode);
- if (canRaiseOverGroupBy(parentNode, accessNode, aggregates, metadata, capFinder)) {
+ if (canRaiseOverGroupBy(parentNode, accessNode, aggregates, metadata, capFinder, record)) {
return performRaise(rootNode, accessNode, parentNode);
}
return null;
@@ -180,7 +184,7 @@
if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
return null;
}
- if (canRaiseOverSelect(accessNode, metadata, capFinder, parentNode)) {
+ if (canRaiseOverSelect(accessNode, metadata, capFinder, parentNode, record)) {
RulePushSelectCriteria.satisfyAccessPatterns(parentNode, accessNode);
return performRaise(rootNode, accessNode, parentNode);
}
@@ -212,7 +216,7 @@
}
PlanNode newParent = grandParent.getParent();
//TODO: use costing or heuristics instead of always raising
- PlanNode newRoot = raiseAccessNode(rootNode, accessNode, metadata, capFinder, afterJoinPlanning);
+ PlanNode newRoot = raiseAccessNode(rootNode, accessNode, metadata, capFinder, afterJoinPlanning, record);
if (newRoot == null) {
//return the tree to its original state
parentNode.addFirstChild(accessNode);
@@ -291,7 +295,7 @@
PlanNode accessNode,
Collection<? extends SingleElementSymbol> aggregates,
QueryMetadataInterface metadata,
- CapabilitiesFinder capFinder) throws QueryMetadataException,
+ CapabilitiesFinder capFinder, AnalysisRecord record) throws QueryMetadataException,
TeiidComponentException {
Object modelID = getModelIDFromAccess(accessNode, metadata);
if(modelID == null) {
@@ -299,29 +303,36 @@
}
List<SingleElementSymbol> groupCols = (List<SingleElementSymbol>)groupNode.getProperty(NodeConstants.Info.GROUP_COLS);
if(!CapabilitiesUtil.supportsAggregates(groupCols, modelID, metadata, capFinder)) {
+ recordDebug("cannot push group by, since group by is not supported by source", groupNode, record); //$NON-NLS-1$
return false;
}
if (groupCols != null) {
for (SingleElementSymbol singleElementSymbol : groupCols) {
- if (!canPushSymbol(singleElementSymbol, false, modelID, metadata, capFinder)) {
+ if (!canPushSymbol(singleElementSymbol, false, modelID, metadata, capFinder, record)) {
return false;
}
}
}
if (aggregates != null) {
for (SingleElementSymbol aggregateSymbol : aggregates) {
- if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(aggregateSymbol, modelID, metadata, capFinder)) {
+ if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(aggregateSymbol, modelID, metadata, capFinder, record)) {
return false;
}
}
}
return CapabilitiesUtil.checkElementsAreSearchable(groupCols, metadata, SupportConstants.Element.SEARCHABLE_COMPARE);
}
+
+ private static void recordDebug(String message, PlanNode node, AnalysisRecord record) {
+ if (record != null && record.recordDebug()) {
+ record.println(message + " " + node.nodeToString()); //$NON-NLS-1$
+ }
+ }
static boolean canRaiseOverSort(PlanNode accessNode,
QueryMetadataInterface metadata,
CapabilitiesFinder capFinder,
- PlanNode parentNode) throws QueryMetadataException,
+ PlanNode parentNode, AnalysisRecord record) throws QueryMetadataException,
TeiidComponentException {
// Find the model for this node by getting ACCESS node's model
Object modelID = getModelIDFromAccess(accessNode, metadata);
@@ -333,7 +344,7 @@
List<OrderByItem> sortCols = ((OrderBy)parentNode.getProperty(NodeConstants.Info.SORT_ORDER)).getOrderByItems();
for (OrderByItem symbol : sortCols) {
//TODO: this check shouldn't be necessary, since the order by is not introducing new expressions
- if(! canPushSymbol(symbol.getSymbol(), true, modelID, metadata, capFinder)) {
+ if(! canPushSymbol(symbol.getSymbol(), true, modelID, metadata, capFinder, record)) {
return false;
}
boolean supportsNullOrdering = CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_NULL_ORDERING, modelID, metadata, capFinder);
@@ -407,7 +418,7 @@
static boolean canRaiseOverSelect(PlanNode accessNode,
QueryMetadataInterface metadata,
CapabilitiesFinder capFinder,
- PlanNode parentNode) throws QueryMetadataException,
+ PlanNode parentNode, AnalysisRecord record) throws QueryMetadataException,
TeiidComponentException,
QueryPlannerException {
if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_PHANTOM)) {
@@ -422,6 +433,7 @@
}
if (parentNode.hasBooleanProperty(NodeConstants.Info.IS_HAVING) && !CapabilitiesUtil.supports(Capability.QUERY_HAVING, modelID, metadata, capFinder)) {
+ recordDebug("cannot push having, since having is not supported by source", parentNode, record); //$NON-NLS-1$
return false;
}
@@ -433,7 +445,7 @@
Criteria crit = (Criteria) parentNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
- if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder) ) {
+ if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, modelID, metadata, capFinder, record) ) {
return false;
}
@@ -456,13 +468,14 @@
* @throws QueryMetadataException
* @since 4.1.2
*/
- private static boolean canPushSymbol(SingleElementSymbol symbol, boolean inSelectClause, Object modelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder)
+ private static boolean canPushSymbol(SingleElementSymbol symbol, boolean inSelectClause, Object modelID,
+ QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record)
throws TeiidComponentException, QueryMetadataException {
Expression expr = SymbolMap.getExpression(symbol);
// Do the normal checks
- if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(expr, modelID, metadata, capFinder)) {
+ if(! CriteriaCapabilityValidatorVisitor.canPushLanguageObject(expr, modelID, metadata, capFinder, record)) {
return false;
}
@@ -499,7 +512,8 @@
* @return The modelID if the raise can proceed and what common model these combined
* nodes will be sent to
*/
- private static Object canRaiseOverJoin(Object modelId, PlanNode joinNode, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, boolean afterJoinPlanning)
+ private static Object canRaiseOverJoin(Object modelId, PlanNode joinNode, QueryMetadataInterface metadata,
+ CapabilitiesFinder capFinder, boolean afterJoinPlanning, AnalysisRecord record)
throws QueryMetadataException, TeiidComponentException {
List crits = (List) joinNode.getProperty(NodeConstants.Info.JOIN_CRITERIA);
@@ -536,14 +550,14 @@
}
}
- return canRaiseOverJoin(joinNode.getChildren(), metadata, capFinder, crits, type);
+ return canRaiseOverJoin(joinNode.getChildren(), metadata, capFinder, crits, type, record);
}
static Object canRaiseOverJoin(List<PlanNode> children,
QueryMetadataInterface metadata,
CapabilitiesFinder capFinder,
List<Criteria> crits,
- JoinType type) throws QueryMetadataException,
+ JoinType type, AnalysisRecord record) throws QueryMetadataException,
TeiidComponentException {
//we only want to consider binary joins
if (children.size() != 2) {
@@ -602,7 +616,7 @@
List<Object> rightIds = null;
GroupSymbol leftGroup = null;
for (Criteria crit : crits) {
- if (!isSupportedJoinCriteria(sjc, crit, accessModelID, metadata, capFinder)) {
+ if (!isSupportedJoinCriteria(sjc, crit, accessModelID, metadata, capFinder, record)) {
return null;
}
if (sjc != SupportedJoinCriteria.KEY) {
@@ -663,9 +677,10 @@
/**
* Checks criteria one predicate at a time. Only tests up to the equi restriction.
*/
- static boolean isSupportedJoinCriteria(SupportedJoinCriteria sjc, Criteria crit, Object accessModelID, QueryMetadataInterface metadata, CapabilitiesFinder capFinder)
+ static boolean isSupportedJoinCriteria(SupportedJoinCriteria sjc, Criteria crit, Object accessModelID,
+ QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record)
throws QueryMetadataException, TeiidComponentException {
- if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, accessModelID, metadata, capFinder) ) {
+ if(!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(crit, accessModelID, metadata, capFinder, record) ) {
return false;
}
if (sjc == SupportedJoinCriteria.ANY) {
Modified: branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java
===================================================================
--- branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCalculateCostUtil.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -24,6 +24,9 @@
import static org.junit.Assert.*;
+import java.util.Arrays;
+
+import org.junit.Ignore;
import org.junit.Test;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.core.TeiidComponentException;
@@ -35,7 +38,6 @@
import org.teiid.query.optimizer.relational.plantree.NodeConstants;
import org.teiid.query.optimizer.relational.plantree.NodeFactory;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
-import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.processor.TestVirtualDepJoin;
import org.teiid.query.processor.relational.RelationalPlan;
@@ -47,7 +49,7 @@
import org.teiid.query.unittest.FakeMetadataObject;
import org.teiid.query.util.CommandContext;
-
+ at SuppressWarnings("nls")
public class TestCalculateCostUtil {
// =====================================================================
@@ -303,6 +305,21 @@
float cost = NewCalculateCostUtil.computeCostForTree(joinNode, metadata);
assertTrue(cost == NewCalculateCostUtil.UNKNOWN_VALUE);
}
+
+ @Ignore("this logic needs to be refined to work better")
+ @Test public void testEstimateJoinNodeCostOneUnknown() throws Exception {
+ QueryMetadataInterface metadata = FakeMetadataFactory.example4();
+ PlanNode joinNode = helpGetJoinNode(NewCalculateCostUtil.UNKNOWN_VALUE, 500, JoinType.JOIN_INNER);
+ joinNode.setProperty(NodeConstants.Info.JOIN_CRITERIA, Arrays.asList(helpGetCriteria("pm1.g1.e1 = pm1.g2.e1", metadata)));
+ float cost = NewCalculateCostUtil.computeCostForTree(joinNode, metadata);
+ assertEquals(10000, cost, 0);
+ }
+
+ @Test public void testEstimateNdvPostJoin() throws Exception {
+ String query = "SELECT account FROM US.Accounts, Europe.CustAccts, CustomerMaster.Customers where account + accid + CustomerMaster.Customers.id = 1000000"; //$NON-NLS-1$
+
+ helpTestQuery(1E9f, query, new String[] {"SELECT g_0.accid FROM Europe.CustAccts AS g_0", "SELECT g_0.id FROM CustomerMaster.Customers AS g_0", "SELECT g_0.account FROM US.Accounts AS g_0"});
+ }
/**
* cases 2159 and 2160, defect 14998
@@ -732,10 +749,17 @@
op +
"SELECT id, convert(accid / 10000, long), mod(accid, 10000), convert(type, integer), amount, 'EU' from Europe.CustAccts"; //$NON-NLS-1$
- RelationalPlan plan = (RelationalPlan)TestOptimizer.helpPlan(query, TestVirtualDepJoin.exampleVirtualDepJoin(), new String[] {"SELECT g_0.customer, g_0.account, g_0.txnid, g_0.txn, g_0.pennies FROM US.Accounts AS g_0 WHERE g_0.txn <> 'X'", "SELECT g_0.id, g_0.accid, g_0.type, g_0.amount FROM Europe.CustAccts AS g_0"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ //$NON-NLS-2$
+ String[] expected = new String[] {"SELECT g_0.customer, g_0.account, g_0.txnid, g_0.txn, g_0.pennies FROM US.Accounts AS g_0 WHERE g_0.txn <> 'X'", "SELECT g_0.id, g_0.accid, g_0.type, g_0.amount FROM Europe.CustAccts AS g_0"};
+ helpTestQuery(cost, query, expected);
+ }
+
+ private void helpTestQuery(float cost, String query, String[] expected)
+ throws TeiidComponentException, TeiidProcessingException {
+ RelationalPlan plan = (RelationalPlan)TestOptimizer.helpPlan(query, TestVirtualDepJoin.exampleVirtualDepJoin(), expected, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$ //$NON-NLS-2$
+
assertEquals(cost, plan.getRootNode().getEstimateNodeCardinality());
- }
+ }
@Test public void testUnion() throws Exception {
helpTestSetOp("UNION ", 1375000.0f); //$NON-NLS-1$
Modified: branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java
===================================================================
--- branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestCriteriaCapabilityValidatorVisitor.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -51,7 +51,7 @@
QueryResolver.resolveCriteria(criteria, metadata);
- assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(criteria, modelID, metadata, capFinder)); //$NON-NLS-1$
+ assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(criteria, modelID, metadata, capFinder, null)); //$NON-NLS-1$
} catch(QueryMetadataException e) {
if (!expectException) {
throw new RuntimeException(e);
@@ -68,7 +68,7 @@
QueryResolver.resolveCommand(command, metadata);
- assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(command, modelID, metadata, capFinder)); //$NON-NLS-1$
+ assertEquals("Got incorrect isValid flag", isValid, CriteriaCapabilityValidatorVisitor.canPushLanguageObject(command, modelID, metadata, capFinder, null)); //$NON-NLS-1$
} catch(QueryMetadataException e) {
if (!expectException) {
throw new RuntimeException(e);
Modified: branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
===================================================================
--- branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java 2010-09-22 21:11:32 UTC (rev 2596)
+++ branches/7.1.x/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java 2010-09-22 21:14:19 UTC (rev 2597)
@@ -213,9 +213,7 @@
null,
null,
joinCriteria,
- expectedMadeDependent);
-
-
+ expectedMadeDependent, null, null);
}
/**
@@ -253,7 +251,7 @@
Criteria atomicRequestCrit2a, //optional
Collection atomicJoinCriteria2, //optional
Collection joinCriteria,
- int expectedMadeDependent) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
+ int expectedMadeDependent, Number expectedCost1, Number expectedCost2) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
//EXAMPLE:
// Project(groups=[])
// Join(groups=[], props={21=joinCriteria, 23=true, 22=INNER JOIN})
@@ -407,6 +405,10 @@
Float cost2 = (Float)accessNode2.getProperty(NodeConstants.Info.EST_CARDINALITY);
assertNotNull(cost2);
assertNotNull(cost1);
+ if (expectedCost1 != null) {
+ assertEquals(expectedCost1.longValue(), cost1.longValue());
+ assertEquals(expectedCost2.longValue(), cost2.longValue());
+ }
}
// ################################## ACTUAL TESTS ################################
@@ -574,9 +576,9 @@
atomicCrit2a,
atomicJoinCrits2,
crits,
- expected);
+ expected, -1, 57734);
}
-
+
/**
* Tests that heuristics will take cardinality of a group into account when
* making a dependent join.
@@ -1064,7 +1066,7 @@
atomicCrit2a,
atomicJoinCrits2,
crits,
- expected);
+ expected, 1000, 1);
}
public void testCardinalityWithAtomicCrossJoin() throws Exception {
@@ -1110,7 +1112,7 @@
atomicCrit2a,
atomicJoinCrits2,
crits,
- expected);
+ expected, 1000, 1E5);
}
public void testCardinalityWithAtomicCrossJoin2() throws Exception {
@@ -1156,7 +1158,7 @@
atomicCrit2a,
atomicJoinCrits2,
crits,
- expected);
+ expected, 1000, 9999899648l);
}
// ################################## TEST SUITE ################################
More information about the teiid-commits
mailing list