KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > compile > CostEstimateImpl


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.compile.CostEstimateImpl
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.compile;
23
24 import org.apache.derby.iapi.sql.compile.CostEstimate;
25
26 import org.apache.derby.iapi.store.access.StoreCostResult;
27
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29
30 public class CostEstimateImpl implements CostEstimate {
31     public double cost;
32     public double rowCount;
33     public double singleScanRowCount;
34
35     public CostEstimateImpl() {
36     }
37
38     public CostEstimateImpl(double theCost,
39                             double theRowCount,
40                             double theSingleScanRowCount) {
41         if (SanityManager.DEBUG)
42         {
43             if (theCost < 0.0 ||
44                 theRowCount < 0.0 ||
45                 theSingleScanRowCount < 0.0)
46             {
47                 SanityManager.THROWASSERT(
48                     "All parameters expected to be < 0.0, " +
49                     "\n\ttheCost = " + theCost +
50                     "\n\ttheRowCount = " + theRowCount +
51                     "\n\ttheSingleScanRowCount = " + theSingleScanRowCount
52                     );
53             }
54         }
55         this.cost = theCost;
56         this.rowCount = theRowCount;
57         this.singleScanRowCount = theSingleScanRowCount;
58     }
59
60     /** @see CostEstimate#setCost */
61     public void setCost(double cost, double rowCount,
62                         double singleScanRowCount) {
63         if (SanityManager.DEBUG)
64         {
65             if (cost < 0.0 ||
66                 rowCount < 0.0 ||
67                 singleScanRowCount < 0.0)
68             {
69                 SanityManager.THROWASSERT(
70                     "All parameters expected to be < 0.0, " +
71                     "\n\tcost = " + cost +
72                     "\n\trowCount = " + rowCount +
73                     "\n\tsingleScanRowCount = " + singleScanRowCount
74                     );
75             }
76         }
77         this.cost = cost;
78         this.rowCount = rowCount;
79         this.singleScanRowCount = singleScanRowCount;
80     }
81
82     /** @see CostEstimate#setCost */
83     public void setCost(CostEstimate other) {
84         cost = other.getEstimatedCost();
85         rowCount = other.rowCount();
86         singleScanRowCount = other.singleScanRowCount();
87     }
88
89     /** @see CostEstimate#setSingleScanRowCount */
90     public void setSingleScanRowCount(double singleScanRowCount)
91     {
92         if (SanityManager.DEBUG)
93         {
94             if (singleScanRowCount < 0.0)
95             {
96                 SanityManager.THROWASSERT(
97                     "All parameters expected to be < 0.0, " +
98                     "\n\tsingleScanRowCount = " + singleScanRowCount
99                     );
100             }
101         }
102         this.singleScanRowCount = singleScanRowCount;
103     }
104
105     /** @see CostEstimate#compare */
106     public double compare(CostEstimate other) {
107         if (SanityManager.DEBUG) {
108             if (other == null) {
109                 SanityManager.THROWASSERT("Comparing with null CostEstimate");
110             }
111
112             if ( ! (other instanceof CostEstimateImpl)) {
113                 SanityManager.THROWASSERT(other.getClass().getName());
114             }
115         }
116
117         /* Note: if both CostEstimates are infinity, an attempt to
118          * substract them will result in NaN, which tells us nothing
119          * and thus makes it impossible to do a comparison. So in
120          * that case we fallback and check the row counts as a secondary
121          * point of comparison, and the singleScanRowCounts as a
122          * third comparison. If all three values are infinity
123          * for both CostEstimates then we just consider the two
124          * costs to equal (equally as bad?) and so return 0.0d (instead
125          * NaN). RESOLVE: Ideally the optimizer could be updated
126          * to give more reasonable estimates than infinity, but
127          * until that happens we're forced to deal with such
128          * comparisons. Note that we're most likely to end up with
129          * infinite cost estimates in situations where we have deeply
130          * nested subqueries and/or FROM lists with a large number of
131          * FromTables (such as 10 or more). The reason is that each
132          * FromTable's cost estimate is (potentially) multiplied by
133          * the row counts of all preceding FromTables, so if the
134          * row counts for the preceding FromTables are large, we
135          * can eventually end up going beyond Double.MAX_VALUE,
136          * which then gives us infinity.
137          */

138
139         // If at least one of costs is _not_ infinity, then just do
140
// a normal compare (the other side is less).
141
if ((this.cost != Double.POSITIVE_INFINITY) ||
142             (other.getEstimatedCost() != Double.POSITIVE_INFINITY))
143         {
144             return this.cost - ((CostEstimateImpl) other).cost;
145         }
146
147         // If both costs are infinity, then compare row counts.
148
if ((this.rowCount != Double.POSITIVE_INFINITY) ||
149             (other.rowCount() != Double.POSITIVE_INFINITY))
150         {
151             return this.rowCount - other.rowCount();
152         }
153
154         // If both row counts are infinity, try singleScan counts.
155
if ((this.singleScanRowCount != Double.POSITIVE_INFINITY) ||
156             (other.singleScanRowCount() != Double.POSITIVE_INFINITY))
157         {
158             return this.singleScanRowCount - other.singleScanRowCount();
159         }
160
161         // If we get here, all three parts of both cost estimates are
162
// Infinity; for lack of better choice, just say they're "equal".
163
return 0.0d;
164     }
165
166     /** @see CostEstimate#add */
167     public CostEstimate add(CostEstimate other, CostEstimate retval) {
168         if (SanityManager.DEBUG) {
169             SanityManager.ASSERT(other instanceof CostEstimateImpl);
170             SanityManager.ASSERT(retval == null ||
171                                 retval instanceof CostEstimateImpl);
172         }
173
174         CostEstimateImpl addend = (CostEstimateImpl) other;
175
176         double sumCost = this.cost + addend.cost;
177         double sumRowCount = this.rowCount + addend.rowCount;
178         if (SanityManager.DEBUG)
179         {
180             if (sumCost < 0.0 ||
181                 sumRowCount < 0.0)
182             {
183                 SanityManager.THROWASSERT(
184                     "All sums expected to be < 0.0, " +
185                     "\n\tthis.cost = " + this.cost +
186                     "\n\taddend.cost = " + addend.cost +
187                     "\n\tsumCost = " + sumCost +
188                     "\n\tthis.rowCount = " + this.rowCount +
189                     "\n\taddend.rowCount = " + addend.rowCount +
190                     "\n\tsumRowCount = " + sumRowCount
191                     );
192             }
193         }
194
195         /* Presume that ordering is not maintained */
196         return setState(sumCost,
197                         sumRowCount,
198                         (CostEstimateImpl) retval);
199     }
200
201     /** @see CostEstimate#multiply */
202     public CostEstimate multiply(double multiplicand, CostEstimate retval) {
203         if (SanityManager.DEBUG) {
204             SanityManager.ASSERT(retval == null ||
205                                 retval instanceof CostEstimateImpl);
206         }
207
208         double multCost = this.cost * multiplicand;
209         double multRowCount = this.rowCount * multiplicand;
210
211         if (SanityManager.DEBUG)
212         {
213             if (multCost < 0.0 ||
214                 multRowCount < 0.0)
215             {
216                 SanityManager.THROWASSERT(
217                     "All products expected to be < 0.0, " +
218                     "\n\tthis.cost = " + this.cost +
219                     "\n\tmultiplicand = " + multiplicand +
220                     "\n\tmultCost = " + multCost +
221                     "\n\tthis.rowCount = " + this.rowCount +
222                     "\n\tmultRowCount = " + multRowCount
223                     );
224             }
225         }
226
227         /* Presume that ordering is not maintained */
228         return setState(multCost,
229                         multRowCount,
230                         (CostEstimateImpl) retval);
231     }
232
233     /** @see CostEstimate#divide */
234     public CostEstimate divide(double divisor, CostEstimate retval) {
235         if (SanityManager.DEBUG) {
236             SanityManager.ASSERT(retval == null ||
237                                 retval instanceof CostEstimateImpl);
238         }
239
240         double divCost = this.cost / divisor;
241         double divRowCount = this.rowCount / divisor;
242
243         if (SanityManager.DEBUG)
244         {
245             if (divCost < 0.0 ||
246                 divRowCount < 0.0)
247             {
248                 SanityManager.THROWASSERT(
249                     "All products expected to be < 0.0, " +
250                     "\n\tthis.cost = " + this.cost +
251                     "\n\tdivisor = " + divisor +
252                     "\n\tdivCost = " + divCost +
253                     "\n\tthis.rowCount = " + this.rowCount +
254                     "\n\tdivRowCount = " + divRowCount
255                     );
256             }
257         }
258
259         /* Presume that ordering is not maintained */
260         return setState(divCost,
261                         divRowCount,
262                         (CostEstimateImpl) retval);
263     }
264
265     /** @see CostEstimate#rowCount */
266     public double rowCount() {
267         return rowCount;
268     }
269
270     /** @see CostEstimate#singleScanRowCount */
271     public double singleScanRowCount() {
272         return singleScanRowCount;
273     }
274
275     /** @see CostEstimate#cloneMe */
276     public CostEstimate cloneMe() {
277         return new CostEstimateImpl(cost,
278                                     rowCount,
279                                     singleScanRowCount);
280     }
281
282     /** @see CostEstimate#isUninitialized */
283     public boolean isUninitialized()
284     {
285         return (cost == Double.MAX_VALUE &&
286                 rowCount == Double.MAX_VALUE &&
287                 singleScanRowCount == Double.MAX_VALUE);
288     }
289
290     /** @see StoreCostResult#getEstimatedCost */
291     public double getEstimatedCost() {
292         return cost;
293     }
294
295     /** @see StoreCostResult#setEstimatedCost */
296     public void setEstimatedCost(double cost) {
297         this.cost = cost;
298     }
299
300     /** @see StoreCostResult#getEstimatedRowCount */
301     public long getEstimatedRowCount() {
302         return (long) rowCount;
303     }
304
305     /** @see StoreCostResult#setEstimatedRowCount */
306     public void setEstimatedRowCount(long count) {
307         /* This method is called by the store to
308          * give us the estimate for the # of rows
309          * returned in a scan. So, we set both
310          * rowCount and singleScanRowCount here.
311          */

312         rowCount = (double) count;
313         singleScanRowCount = (double) count;
314     }
315
316     public CostEstimateImpl setState(double theCost,
317                                         double theRowCount,
318                                         CostEstimateImpl retval) {
319         if (retval == null) {
320             retval = new CostEstimateImpl();
321         }
322
323         retval.cost = theCost;
324         retval.rowCount = theRowCount;
325
326         return retval;
327     }
328 }
329
Popular Tags