Skip to content

Commit ae42776

Browse files
committed
More realistic cardinality adjustments for unmatchable booleans, this should also fix #7904: FB5 bad plan for query
1 parent ff6bbf9 commit ae42776

File tree

1 file changed

+46
-22
lines changed

1 file changed

+46
-22
lines changed

src/jrd/optimizer/Optimizer.h

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -356,55 +356,79 @@ class Optimizer : public Firebird::PermanentStorage
356356

357357
static double getSelectivity(const BoolExprNode* node)
358358
{
359-
if (const auto listNode = nodeAs<InListBoolNode>(node))
359+
auto factor = REDUCE_SELECTIVITY_FACTOR_OTHER;
360+
361+
if (const auto binaryNode = nodeAs<BinaryBoolNode>(node))
360362
{
361-
const auto selectivity = REDUCE_SELECTIVITY_FACTOR_EQUALITY *
362-
listNode->list->items.getCount();
363-
return MIN(selectivity, MAXIMUM_SELECTIVITY);
363+
if (binaryNode->blrOp == blr_and)
364+
factor = getSelectivity(binaryNode->arg1) * getSelectivity(binaryNode->arg2);
365+
else if (binaryNode->blrOp == blr_or)
366+
factor = getSelectivity(binaryNode->arg1) + getSelectivity(binaryNode->arg2);
367+
else
368+
fb_assert(false);
364369
}
365-
366-
if (nodeIs<MissingBoolNode>(node))
367-
return REDUCE_SELECTIVITY_FACTOR_EQUALITY;
368-
369-
if (const auto cmpNode = nodeAs<ComparativeBoolNode>(node))
370+
else if (const auto listNode = nodeAs<InListBoolNode>(node))
371+
{
372+
factor = REDUCE_SELECTIVITY_FACTOR_EQUALITY * listNode->list->items.getCount();
373+
}
374+
else if (nodeIs<MissingBoolNode>(node))
375+
{
376+
factor = REDUCE_SELECTIVITY_FACTOR_EQUALITY;
377+
}
378+
else if (const auto cmpNode = nodeAs<ComparativeBoolNode>(node))
370379
{
371380
switch (cmpNode->blrOp)
372381
{
373382
case blr_eql:
374383
case blr_equiv:
375-
return REDUCE_SELECTIVITY_FACTOR_EQUALITY;
384+
factor = REDUCE_SELECTIVITY_FACTOR_EQUALITY;
385+
break;
376386

377387
case blr_gtr:
378388
case blr_geq:
379-
return REDUCE_SELECTIVITY_FACTOR_GREATER;
389+
factor = REDUCE_SELECTIVITY_FACTOR_GREATER;
390+
break;
380391

381392
case blr_lss:
382393
case blr_leq:
383-
return REDUCE_SELECTIVITY_FACTOR_LESS;
394+
factor = REDUCE_SELECTIVITY_FACTOR_LESS;
395+
break;
384396

385397
case blr_between:
386-
return REDUCE_SELECTIVITY_FACTOR_BETWEEN;
398+
factor = REDUCE_SELECTIVITY_FACTOR_BETWEEN;
399+
break;
387400

388401
case blr_starting:
389-
return REDUCE_SELECTIVITY_FACTOR_STARTING;
402+
factor = REDUCE_SELECTIVITY_FACTOR_STARTING;
403+
break;
390404

391405
default:
392406
break;
393407
}
394408
}
395409

396-
return REDUCE_SELECTIVITY_FACTOR_OTHER;
410+
// dimitr:
411+
//
412+
// Adjust to values similar to those used when the index selectivity is missing.
413+
// The final value will be in the range [0.1 .. 0.5] that also matches the v3/v4 logic.
414+
// This estimation is quite pessimistic but it seems to work better in practice,
415+
// especially when multiple unmatchable booleans are used.
416+
417+
const auto adjustment = DEFAULT_SELECTIVITY / REDUCE_SELECTIVITY_FACTOR_EQUALITY;
418+
const auto selectivity = factor * adjustment;
419+
420+
return MIN(selectivity, MAXIMUM_SELECTIVITY / 2);
397421
}
398422

399423
static void adjustSelectivity(double& selectivity, double factor, double cardinality)
400424
{
401-
if (cardinality)
402-
{
403-
const auto minSelectivity = 1 / cardinality;
404-
const auto diffSelectivity = selectivity > minSelectivity ?
405-
selectivity - minSelectivity : 0;
406-
selectivity = minSelectivity + diffSelectivity * factor;
407-
}
425+
if (!cardinality)
426+
cardinality = DEFAULT_CARDINALITY;
427+
428+
const auto minSelectivity = MAXIMUM_SELECTIVITY / cardinality;
429+
const auto diffSelectivity = selectivity > minSelectivity ?
430+
selectivity - minSelectivity : 0;
431+
selectivity = minSelectivity + diffSelectivity * factor;
408432
}
409433

410434
static RecordSource* compile(thread_db* tdbb, CompilerScratch* csb, RseNode* rse)

0 commit comments

Comments
 (0)