From e08a06175b0754f6069a33742358bc61764ca6e7 Mon Sep 17 00:00:00 2001 From: Ralph Gasser Date: Fri, 24 May 2024 09:35:59 +0200 Subject: [PATCH] Fixes an issue in selectivity calculation, which leads to absolute values instead of relative ones. --- .../selectivity/NaiveSelectivityCalculator.kt | 11 +++-- .../values/AbstractValueStatistics.kt | 47 ++++++++++--------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/selectivity/NaiveSelectivityCalculator.kt b/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/selectivity/NaiveSelectivityCalculator.kt index 734ad838d..e58bb0281 100644 --- a/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/selectivity/NaiveSelectivityCalculator.kt +++ b/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/selectivity/NaiveSelectivityCalculator.kt @@ -30,7 +30,11 @@ object NaiveSelectivityCalculator { is BooleanPredicate.IsNull -> this.estimateIsNull(predicate, statistics) is BooleanPredicate.Comparison -> this.estimateComparison(predicate, statistics) is BooleanPredicate.Not -> Selectivity(1.0f - this.estimate(predicate.p, statistics).value) - is BooleanPredicate.And -> this.estimate(predicate.p1, statistics) * this.estimate(predicate.p2, statistics) + is BooleanPredicate.And -> { + val pp1 = this.estimate(predicate.p1, statistics) + val pp2 = this.estimate(predicate.p2, statistics) + pp1 * pp2 + } is BooleanPredicate.Or -> { val pp1 = this.estimate(predicate.p1, statistics) val pp2 = this.estimate(predicate.p2, statistics) @@ -69,8 +73,9 @@ object NaiveSelectivityCalculator { val right = predicate.operator.right return when { left is Binding.Literal && right is Binding.Literal -> if (left.getValue() == right.getValue()) Selectivity.ALL else Selectivity.NOTHING - left is Binding.Literal && right is Binding.Column -> statistics[right.column]?.estimateSelectivity(predicate) ?: Selectivity.DEFAULT - left is Binding.Column && right is Binding.Literal -> statistics[left.column]?.estimateSelectivity(predicate) ?: Selectivity.DEFAULT + left is Binding.Literal && right is Binding.Column -> statistics[right.physical]?.estimateSelectivity(predicate) ?: Selectivity.DEFAULT + left is Binding.Column && right is Binding.Literal -> statistics[left.physical]?.estimateSelectivity(predicate) ?: Selectivity.DEFAULT + left is Binding.Column && right is Binding.LiteralList -> statistics[left.physical]?.estimateSelectivity(predicate) ?: Selectivity.DEFAULT else -> Selectivity.DEFAULT } } diff --git a/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/values/AbstractValueStatistics.kt b/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/values/AbstractValueStatistics.kt index aaff53c82..346424607 100644 --- a/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/values/AbstractValueStatistics.kt +++ b/cottontaildb-dbms/src/main/kotlin/org/vitrivr/cottontail/dbms/statistics/values/AbstractValueStatistics.kt @@ -75,28 +75,29 @@ sealed class AbstractValueStatistics(override val type: Types) : V * @return [Selectivity] estimate. */ context(BindingContext, Tuple) - override fun estimateSelectivity(predicate: BooleanPredicate.Comparison): Selectivity = when(val operator = predicate.operator){ - /* =: Textbook definition using estimate for number if distinct entries. */ - is ComparisonOperator.Equal -> Selectivity(this.numberOfEntries.toFloat() / this.numberOfDistinctEntries.toFloat()) // Case Equality = - - /* !=: Textbook definition using estimate for number if distinct entries. */ - is ComparisonOperator.NotEqual -> Selectivity(this.numberOfEntries.toFloat() * (this.numberOfDistinctEntries.toFloat() - 1f) / this.numberOfDistinctEntries.toFloat()) //Case Not-equals (like A != 10) - - /* <, >, <=, >=: Textbook definition. Assumption is, that 1/3 of the collection is selected (see [1]) */ - is ComparisonOperator.Greater, - is ComparisonOperator.Less, - is ComparisonOperator.GreaterEqual, - is ComparisonOperator.LessEqual -> Selectivity(this.numberOfEntries.toFloat() / 3f) - - /* BETWEEN: Assumption is, that it returns fewer tuples than a less/greater operator (since it's a composition of both using AND). */ - is ComparisonOperator.Between -> Selectivity(this.numberOfEntries.toFloat() / 6f) // - - /* IN: Assumption is, that all elements in IN are matches (worst-case). */ - is ComparisonOperator.In -> Selectivity(operator.right.size() * this.numberOfEntries.toFloat() / this.numberOfDistinctEntries.toFloat()) - - // Default case: - else -> Selectivity.DEFAULT + override fun estimateSelectivity(predicate: BooleanPredicate.Comparison): Selectivity { + val selected = when(val operator = predicate.operator){ + /* =: Textbook definition using estimate for number of distinct entries. */ + is ComparisonOperator.Equal -> this.numberOfEntries.toFloat() / this.numberOfDistinctEntries.toFloat() + + /* !=: Textbook definition using estimate for number if distinct entries. */ + is ComparisonOperator.NotEqual ->this.numberOfEntries.toFloat() * (this.numberOfDistinctEntries.toFloat() - 1f) / this.numberOfDistinctEntries.toFloat() //Case Not-equals (like A != 10) + + /* <, >, <=, >=: Textbook definition. Assumption is, that 1/3 of the collection is selected (see [1]) */ + is ComparisonOperator.Greater, + is ComparisonOperator.Less, + is ComparisonOperator.GreaterEqual, + is ComparisonOperator.LessEqual -> this.numberOfEntries.toFloat() / 3f + + /* BETWEEN: Assumption is, that it returns fewer tuples than a less/greater operator (since it's a composition of both using AND). */ + is ComparisonOperator.Between -> this.numberOfEntries.toFloat() / 6f // + + /* IN: Assumption is, that all elements IN are matches (worst-case). */ + is ComparisonOperator.In -> (operator.right.size() * this.numberOfEntries.toFloat()) / this.numberOfDistinctEntries.toFloat() + + // Default case: + else -> this.numberOfEntries / 3f + } + return Selectivity(selected / this.numberOfEntries.toFloat()) } - - }