001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.CostEstimateImpl
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.sql.compile.CostEstimate;
025:
026: import org.apache.derby.iapi.store.access.StoreCostResult;
027:
028: import org.apache.derby.iapi.services.sanity.SanityManager;
029:
030: public class CostEstimateImpl implements CostEstimate {
031: public double cost;
032: public double rowCount;
033: public double singleScanRowCount;
034:
035: public CostEstimateImpl() {
036: }
037:
038: public CostEstimateImpl(double theCost, double theRowCount,
039: double theSingleScanRowCount) {
040: if (SanityManager.DEBUG) {
041: if (theCost < 0.0 || theRowCount < 0.0
042: || theSingleScanRowCount < 0.0) {
043: SanityManager
044: .THROWASSERT("All parameters expected to be < 0.0, "
045: + "\n\ttheCost = "
046: + theCost
047: + "\n\ttheRowCount = "
048: + theRowCount
049: + "\n\ttheSingleScanRowCount = "
050: + theSingleScanRowCount);
051: }
052: }
053: this .cost = theCost;
054: this .rowCount = theRowCount;
055: this .singleScanRowCount = theSingleScanRowCount;
056: }
057:
058: /** @see CostEstimate#setCost */
059: public void setCost(double cost, double rowCount,
060: double singleScanRowCount) {
061: if (SanityManager.DEBUG) {
062: if (cost < 0.0 || rowCount < 0.0
063: || singleScanRowCount < 0.0) {
064: SanityManager
065: .THROWASSERT("All parameters expected to be < 0.0, "
066: + "\n\tcost = "
067: + cost
068: + "\n\trowCount = "
069: + rowCount
070: + "\n\tsingleScanRowCount = "
071: + singleScanRowCount);
072: }
073: }
074: this .cost = cost;
075: this .rowCount = rowCount;
076: this .singleScanRowCount = singleScanRowCount;
077: }
078:
079: /** @see CostEstimate#setCost */
080: public void setCost(CostEstimate other) {
081: cost = other.getEstimatedCost();
082: rowCount = other.rowCount();
083: singleScanRowCount = other.singleScanRowCount();
084: }
085:
086: /** @see CostEstimate#setSingleScanRowCount */
087: public void setSingleScanRowCount(double singleScanRowCount) {
088: if (SanityManager.DEBUG) {
089: if (singleScanRowCount < 0.0) {
090: SanityManager
091: .THROWASSERT("All parameters expected to be < 0.0, "
092: + "\n\tsingleScanRowCount = "
093: + singleScanRowCount);
094: }
095: }
096: this .singleScanRowCount = singleScanRowCount;
097: }
098:
099: /** @see CostEstimate#compare */
100: public double compare(CostEstimate other) {
101: if (SanityManager.DEBUG) {
102: if (other == null) {
103: SanityManager
104: .THROWASSERT("Comparing with null CostEstimate");
105: }
106:
107: if (!(other instanceof CostEstimateImpl)) {
108: SanityManager.THROWASSERT(other.getClass().getName());
109: }
110: }
111:
112: /* Note: if both CostEstimates are infinity, an attempt to
113: * substract them will result in NaN, which tells us nothing
114: * and thus makes it impossible to do a comparison. So in
115: * that case we fallback and check the row counts as a secondary
116: * point of comparison, and the singleScanRowCounts as a
117: * third comparison. If all three values are infinity
118: * for both CostEstimates then we just consider the two
119: * costs to equal (equally as bad?) and so return 0.0d (instead
120: * NaN). RESOLVE: Ideally the optimizer could be updated
121: * to give more reasonable estimates than infinity, but
122: * until that happens we're forced to deal with such
123: * comparisons. Note that we're most likely to end up with
124: * infinite cost estimates in situations where we have deeply
125: * nested subqueries and/or FROM lists with a large number of
126: * FromTables (such as 10 or more). The reason is that each
127: * FromTable's cost estimate is (potentially) multiplied by
128: * the row counts of all preceding FromTables, so if the
129: * row counts for the preceding FromTables are large, we
130: * can eventually end up going beyond Double.MAX_VALUE,
131: * which then gives us infinity.
132: */
133:
134: // If at least one of costs is _not_ infinity, then just do
135: // a normal compare (the other side is less).
136: if ((this .cost != Double.POSITIVE_INFINITY)
137: || (other.getEstimatedCost() != Double.POSITIVE_INFINITY)) {
138: return this .cost - ((CostEstimateImpl) other).cost;
139: }
140:
141: // If both costs are infinity, then compare row counts.
142: if ((this .rowCount != Double.POSITIVE_INFINITY)
143: || (other.rowCount() != Double.POSITIVE_INFINITY)) {
144: return this .rowCount - other.rowCount();
145: }
146:
147: // If both row counts are infinity, try singleScan counts.
148: if ((this .singleScanRowCount != Double.POSITIVE_INFINITY)
149: || (other.singleScanRowCount() != Double.POSITIVE_INFINITY)) {
150: return this .singleScanRowCount - other.singleScanRowCount();
151: }
152:
153: // If we get here, all three parts of both cost estimates are
154: // Infinity; for lack of better choice, just say they're "equal".
155: return 0.0d;
156: }
157:
158: /** @see CostEstimate#add */
159: public CostEstimate add(CostEstimate other, CostEstimate retval) {
160: if (SanityManager.DEBUG) {
161: SanityManager.ASSERT(other instanceof CostEstimateImpl);
162: SanityManager.ASSERT(retval == null
163: || retval instanceof CostEstimateImpl);
164: }
165:
166: CostEstimateImpl addend = (CostEstimateImpl) other;
167:
168: double sumCost = this .cost + addend.cost;
169: double sumRowCount = this .rowCount + addend.rowCount;
170: if (SanityManager.DEBUG) {
171: if (sumCost < 0.0 || sumRowCount < 0.0) {
172: SanityManager
173: .THROWASSERT("All sums expected to be < 0.0, "
174: + "\n\tthis.cost = " + this .cost
175: + "\n\taddend.cost = " + addend.cost
176: + "\n\tsumCost = " + sumCost
177: + "\n\tthis.rowCount = "
178: + this .rowCount
179: + "\n\taddend.rowCount = "
180: + addend.rowCount
181: + "\n\tsumRowCount = " + sumRowCount);
182: }
183: }
184:
185: /* Presume that ordering is not maintained */
186: return setState(sumCost, sumRowCount, (CostEstimateImpl) retval);
187: }
188:
189: /** @see CostEstimate#multiply */
190: public CostEstimate multiply(double multiplicand,
191: CostEstimate retval) {
192: if (SanityManager.DEBUG) {
193: SanityManager.ASSERT(retval == null
194: || retval instanceof CostEstimateImpl);
195: }
196:
197: double multCost = this .cost * multiplicand;
198: double multRowCount = this .rowCount * multiplicand;
199:
200: if (SanityManager.DEBUG) {
201: if (multCost < 0.0 || multRowCount < 0.0) {
202: SanityManager
203: .THROWASSERT("All products expected to be < 0.0, "
204: + "\n\tthis.cost = "
205: + this .cost
206: + "\n\tmultiplicand = "
207: + multiplicand
208: + "\n\tmultCost = "
209: + multCost
210: + "\n\tthis.rowCount = "
211: + this .rowCount
212: + "\n\tmultRowCount = "
213: + multRowCount);
214: }
215: }
216:
217: /* Presume that ordering is not maintained */
218: return setState(multCost, multRowCount,
219: (CostEstimateImpl) retval);
220: }
221:
222: /** @see CostEstimate#divide */
223: public CostEstimate divide(double divisor, CostEstimate retval) {
224: if (SanityManager.DEBUG) {
225: SanityManager.ASSERT(retval == null
226: || retval instanceof CostEstimateImpl);
227: }
228:
229: double divCost = this .cost / divisor;
230: double divRowCount = this .rowCount / divisor;
231:
232: if (SanityManager.DEBUG) {
233: if (divCost < 0.0 || divRowCount < 0.0) {
234: SanityManager
235: .THROWASSERT("All products expected to be < 0.0, "
236: + "\n\tthis.cost = "
237: + this .cost
238: + "\n\tdivisor = "
239: + divisor
240: + "\n\tdivCost = "
241: + divCost
242: + "\n\tthis.rowCount = "
243: + this .rowCount
244: + "\n\tdivRowCount = "
245: + divRowCount);
246: }
247: }
248:
249: /* Presume that ordering is not maintained */
250: return setState(divCost, divRowCount, (CostEstimateImpl) retval);
251: }
252:
253: /** @see CostEstimate#rowCount */
254: public double rowCount() {
255: return rowCount;
256: }
257:
258: /** @see CostEstimate#singleScanRowCount */
259: public double singleScanRowCount() {
260: return singleScanRowCount;
261: }
262:
263: /** @see CostEstimate#cloneMe */
264: public CostEstimate cloneMe() {
265: return new CostEstimateImpl(cost, rowCount, singleScanRowCount);
266: }
267:
268: /** @see CostEstimate#isUninitialized */
269: public boolean isUninitialized() {
270: return (cost == Double.MAX_VALUE
271: && rowCount == Double.MAX_VALUE && singleScanRowCount == Double.MAX_VALUE);
272: }
273:
274: /** @see StoreCostResult#getEstimatedCost */
275: public double getEstimatedCost() {
276: return cost;
277: }
278:
279: /** @see StoreCostResult#setEstimatedCost */
280: public void setEstimatedCost(double cost) {
281: this .cost = cost;
282: }
283:
284: /** @see StoreCostResult#getEstimatedRowCount */
285: public long getEstimatedRowCount() {
286: return (long) rowCount;
287: }
288:
289: /** @see StoreCostResult#setEstimatedRowCount */
290: public void setEstimatedRowCount(long count) {
291: /* This method is called by the store to
292: * give us the estimate for the # of rows
293: * returned in a scan. So, we set both
294: * rowCount and singleScanRowCount here.
295: */
296: rowCount = (double) count;
297: singleScanRowCount = (double) count;
298: }
299:
300: public CostEstimateImpl setState(double theCost,
301: double theRowCount, CostEstimateImpl retval) {
302: if (retval == null) {
303: retval = new CostEstimateImpl();
304: }
305:
306: retval.cost = theCost;
307: retval.rowCount = theRowCount;
308:
309: return retval;
310: }
311: }
|