| 173 | // |
| 174 | |
| 175 | void InnerJoin::estimateCost(unsigned position, |
| 176 | const StreamInfo* stream, |
| 177 | double& cost, |
| 178 | double& cardinality) |
| 179 | { |
| 180 | fb_assert(joinedStreams[position].number == stream->number); |
| 181 | |
| 182 | const auto sort = (!position && sortPtr) ? *sortPtr : nullptr; |
| 183 | |
| 184 | // Create the optimizer retrieval generation class and calculate |
| 185 | // which indexes will be used and the total estimated selectivity will be returned |
| 186 | Retrieval retrieval(tdbb, optimizer, stream->number, false, false, sort, true); |
| 187 | const auto candidate = retrieval.getInversion(); |
| 188 | fb_assert(!position || candidate->dependencies); |
| 189 | |
| 190 | // Remember selectivity of this stream |
| 191 | joinedStreams[position].selectivity = candidate->selectivity; |
| 192 | |
| 193 | // Get the stream cardinality |
| 194 | const auto streamCardinality = csb->csb_rpt[stream->number].csb_cardinality; |
| 195 | |
| 196 | // If the table looks like empty during preparation time, we cannot be sure about |
| 197 | // its real cardinality during execution. So, unless we have some index-based |
| 198 | // filtering applied, let's better be pessimistic and avoid hash joining due to |
| 199 | // likely cardinality under-estimation. |
| 200 | const bool avoidHashJoin = (streamCardinality <= MINIMUM_CARDINALITY && !stream->baseIndexes); |
| 201 | |
| 202 | auto currentCardinality = streamCardinality * candidate->selectivity; |
| 203 | |
| 204 | // Given the "first-rows" mode specified (or implied) |
| 205 | // and unless an external sort is to be applied afterwards, |
| 206 | // fake the expected cardinality to look as low as possible |
| 207 | // to estimate the cost just for a single row being produced. |
| 208 | // The same rule is used if the retrieval is unique. |
| 209 | |
| 210 | const bool firstRows = (optimizer->favorFirstRows() && |
| 211 | (!sortPtr || !*sortPtr || candidate->navigated)); |
| 212 | |
| 213 | if ((candidate->unique || firstRows) && currentCardinality > MINIMUM_CARDINALITY) |
| 214 | currentCardinality = MINIMUM_CARDINALITY; |
| 215 | |
| 216 | // Calculate the nested loop cost, it's our default option |
| 217 | const auto loopCost = candidate->cost * cardinality; |
| 218 | cost = loopCost; |
| 219 | |
| 220 | // Consider whether the current stream can be hash-joined to the prior ones. |
| 221 | // Beware conditional retrievals, this is impossible for them. |
| 222 | |
| 223 | if (position && !candidate->condition && !avoidHashJoin) |
| 224 | { |
| 225 | // Calculate the hashing cost. It consists of the following parts: |
| 226 | // - hashed stream retrieval |
| 227 | // - copying rows into the hash table (including hash calculation) |
| 228 | // - probing the hash table and copying the matched rows |
| 229 | |
| 230 | const auto hashCardinality = stream->baseSelectivity * streamCardinality; |
| 231 | const auto hashCost = stream->baseCost + |
| 232 | // hashing cost |
nothing calls this directly
no test coverage detected