You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cloudberry's SelectivityOfPredicate() can estimate that adding an outer-reference predicate to a conjunction increases the fraction of rows passing the filter. This proposal applies damping only when combining outer predicates’ conditional selectivity estimates, then multiplies the result by the local selectivity. It reuses the existing conjunction estimator and honors optimizer_damping_factor_filter instead of a hardcoded default.
Motivation
Motivation
ORCA's CFilterStatsProcessor::SelectivityOfPredicate() estimates predicate selectivity when evaluating candidate index conditions. Its current damping formula can increase the estimated fraction of qualifying rows when another condition is added through AND. This contradicts the fact that a conjunction cannot admit more rows than any of its constituent conditions.
Current mathematical model
Let the predicate be:
$$
L \land E_1 \land \cdots \land E_k,
$$
where $L$ combines the local conditions and each $E_i$ is a conjunct containing outer references.
The function first estimates statistics after applying $L$. Its initial selectivity is:
$$
s_L = \frac{N_L}{N},
$$
where $N$ is the estimated base-table cardinality and $N_L$ is the estimated cardinality after local filtering.
For each outer predicate, it assigns a selectivity multiplier $q_i$:
For a recognized equality between a local column and an outer expression, $q_i=1/D_i$, provided the estimated NDV $D_i\ge1$.
Otherwise, it uses the default selectivity $0.4$.
Constant TRUE expressions are ignored.
The NDVs come from the statistics after local filtering. Accordingly, these multipliers can be interpreted as heuristic estimates of the conditional probabilities $P(E_i\mid L)$.
The function first multiplies the estimates:
$$
r_{\mathrm{raw}} = s_L\prod_{i=1}^{k}q_i.
$$
It then counts the outer predicates, adding one for the complete local condition if $s_L<1$:
$$
m = k + \mathbf{1}_{s_L<1}.
$$
If $m \le 1$, no final damping correction is applied:
$$
S_{\mathrm{current}} = r_{\mathrm{raw}}.
$$
If $m > 1$, the function divides the product by the damping correction and caps the result at one:
The coefficient in this final correction is always 0.75, taken from PstatsconfDefault(), rather than the configured optimizer_damping_factor_filter.
Required properties
Let $p_i=P(A_i)$ be the selectivity of predicate $A_i$, for $n$ predicates evaluated over the same population. Their individual selectivities do not determine their conjunction: the result also depends on how the qualifying rows overlap.
Let $F_d(p_1,\ldots,p_n)$ estimate the conjunction at damping coefficient $d\in[0,1]$. Damping should interpolate between independence ($d=1$) and maximum overlap ($d=0$):
Maximum overlap means that every row satisfying the most restrictive predicate also satisfies the others. This model covers dependence that increases overlap relative to independence, not every possible dependence.
A neutral predicate with selectivity one must leave the result unchanged, as must reordering the inputs. For example, selectivities $0.1$ and $0.2$ allow an estimate between $0.02$ and $0.1$.
Applying this to outer predicates
The outer estimates $q_i$ use statistics after local filtering, so we interpret them as approximations to $P(E_i\mid L)$. The probability decomposition is:
Without outer predicates, return $s_L$. With one outer predicate, return $s_Lq_1$ for every coefficient.
Theoretical counterexample
Suppose local filtering retains an estimated 1,000 of 10,000 rows, so $s_L=0.1$. Add an outer equality with $D_1=1$, giving $q_1=1$. This multiplier excludes no locally qualifying rows, so the combined estimate should remain $0.1$.
Instead, the current implementation counts two factors and returns:
Adding a conjunct increases the estimated qualifying population from 1,000 to approximately 1,778 rows. Capping the result at one does not prevent this violation.
Even a cap at $s_L$ would be insufficient: with $s_L=0.1$ and $q_1=0.2$, the current formula returns approximately $0.035556$, exceeding the conditional-model result $s_Lq_1=0.02$.
The change would preserve these bounds and honor the configured damping coefficient in an estimate used for index selection.
SQL demonstrations
Create a 10,000-row inner table and a single-row outer table. The bitmap indexes and disabled hash joins encourage ORCA to consider index conditions containing outer references.
The estimates below refer to the value returned by CFilterStatsProcessor::SelectivityOfPredicate(), which can be inspected in a debugger. They are not necessarily the row estimates shown by EXPLAIN.
SET optimizer = off;
CREATETABLEdamping_inner (
id integer,
a integer,
b integer,
c integer,
z integer
) USING heap DISTRIBUTED RANDOMLY;
INSERT INTO damping_inner
SELECT
n,
n % 10,
(n /10) % 5,
(n /50) % 4,
0FROM generate_series(0, 9999) AS g(n);
CREATETABLEdamping_outer (
b integer,
c integer,
z integer
) USING heap DISTRIBUTED REPLICATED;
INSERT INTO damping_outer VALUES (0, 0, 0);
CREATEINDEXdamping_inner_abczON damping_inner USING bitmap (a, b, c, z);
CREATEINDEXdamping_inner_bczaON damping_inner USING bitmap (b, c, z, a);
ANALYZE damping_inner;
ANALYZE damping_outer;
SET optimizer =on;
SET optimizer_enable_hashjoin = off;
SET optimizer_damping_factor_filter =0.75;
The generated data has the following properties:
Property
Value
Inner rows
10,000
NDV of a
10
NDV of b
5
NDV of c
4
NDV of z
1
1. Local predicate only
EXPLAIN (ANALYZE, TIMING OFF)
SELECT i.*FROM damping_outer AS o
CROSS JOIN damping_inner AS i
WHEREi.a=1;
The query returns exactly 1,000 rows, corresponding to a selectivity of $0.1$. In the debugger, the function returned 0.099999003112316131; the small difference comes from ORCA's normalization of floating-point frequencies.
This is the baseline. Damping does not affect this single equality. The calculations below use the idealized value $s_L=0.1$ for clarity.
2. Add a neutral outer predicate
EXPLAIN (ANALYZE, TIMING OFF)
SELECT i.*FROM damping_outer AS o
CROSS JOIN damping_inner AS i
WHEREi.a=1ANDi.z=o.z;
Both i.z and the single outer row's o.z are zero, so the additional condition excludes no rows:
$$
s_L=0.1,\qquad q_z=1.
$$
The actual output remains 1,000 rows.
Implementation
Calculation
Approximate selectivity
Original
$s_L/0.75^2$
0.177778
Expected
$s_L\times1$
0.1
The original formula increases the estimate when a conjunct is added. Instead, the corrected formula should preserve the baseline estimate, as required.
Implementation
Implementation
We propose keeping the local selectivity separate and applying the existing conjunction estimator only to predicates containing outer references.
Combine conditional outer estimates
Let $s_L$ be the estimated local selectivity and $q_i$ the estimated selectivity of outer predicate $E_i$ within the locally filtered population. For $k$ outer predicates and damping coefficient $d$, the overall estimate is:
$$
S_d=s_L F_d(q_1,\ldots,q_k),
$$
where $F_d$ combines the outer estimates. The local filter is not included in this damping step: it has already been estimated, and its output defines the population to which the outer estimates apply.
The implementation preserves the existing individual estimates: $q_i=1/D_i$ for a recognized outer equality with NDV $D_i\ge1$, and the default selectivity otherwise. Constant TRUE expressions are ignored.
Instead of multiplying these estimates immediately, the function collects their scale factors $SF_i=1/q_i$ and passes them to CScaleFactorUtils::CalcScaleFactorCumulativeConj().
Reuse the existing conjunction formula
The helper sorts the scale factors in descending order. Equivalently, the outer selectivities are ordered as:
$$
q_{(1)}\le q_{(2)}\le\cdots\le q_{(k)},
$$
where $q_{(j)}$ is the selectivity at position $j$ after sorting. For $0<d\le1$ and $k\ge1$, its calculation corresponds to:
At $d=1$, the result is the ordinary product. With one outer predicate, it is $s_Lq_1$. With no outer predicates, the helper returns scale factor one and the result remains $s_L$.
SelectivityOfPredicate() returns the local selectivity divided by the combined outer scale factor. This replaces the old division of the complete product by $0.75^m$ and removes the counting of the local condition as an additional damping factor.
Use the configured coefficient
The helper will receive the active statistics configuration from GetStatsConf(). The final aggregation will therefore honor optimizer_damping_factor_filter instead of constructing a default configuration with coefficient 0.75. This proposal reuses the shared helper without modifying its implementation.
Separate follow-up for zero damping
Explicit handling of optimizer_damping_factor_filter = 0 will be covered by a separate proposal and PR. That change will allow zero in the filter configuration assertion and handle it in the shared conjunction helper as maximum overlap:
type: ProposalProposals of major changes to Cloudberry Database
1 participant
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Proposers
Andrei
Proposal Status
Under Discussion
Abstract
Cloudberry's
SelectivityOfPredicate()can estimate that adding an outer-reference predicate to a conjunction increases the fraction of rows passing the filter. This proposal applies damping only when combining outer predicates’ conditional selectivity estimates, then multiplies the result by the local selectivity. It reuses the existing conjunction estimator and honorsoptimizer_damping_factor_filterinstead of a hardcoded default.Motivation
Motivation
ORCA's
CFilterStatsProcessor::SelectivityOfPredicate()estimates predicate selectivity when evaluating candidate index conditions. Its current damping formula can increase the estimated fraction of qualifying rows when another condition is added throughAND. This contradicts the fact that a conjunction cannot admit more rows than any of its constituent conditions.Current mathematical model
Let the predicate be:
where$L$ combines the local conditions and each $E_i$ is a conjunct containing outer references.
The function first estimates statistics after applying$L$ . Its initial selectivity is:
where$N$ is the estimated base-table cardinality and $N_L$ is the estimated cardinality after local filtering.
For each outer predicate, it assigns a selectivity multiplier$q_i$ :
TRUEexpressions are ignored.The NDVs come from the statistics after local filtering. Accordingly, these multipliers can be interpreted as heuristic estimates of the conditional probabilities$P(E_i\mid L)$ .
The function first multiplies the estimates:
It then counts the outer predicates, adding one for the complete local condition if$s_L<1$ :
If$m \le 1$ , no final damping correction is applied:
If$m > 1$ , the function divides the product by the damping correction and caps the result at one:
The coefficient in this final correction is always
0.75, taken fromPstatsconfDefault(), rather than the configuredoptimizer_damping_factor_filter.Required properties
Let$p_i=P(A_i)$ be the selectivity of predicate $A_i$ , for $n$ predicates evaluated over the same population. Their individual selectivities do not determine their conjunction: the result also depends on how the qualifying rows overlap.
Let$F_d(p_1,\ldots,p_n)$ estimate the conjunction at damping coefficient $d\in[0,1]$ . Damping should interpolate between independence ($d=1$ ) and maximum overlap ($d=0$ ):
Maximum overlap means that every row satisfying the most restrictive predicate also satisfies the others. This model covers dependence that increases overlap relative to independence, not every possible dependence.
The estimate should satisfy:
The upper bound is required by conjunction semantics; the product lower bound belongs to the chosen damping model.
Adding a predicate with selectivity$p_{n+1}$ must not increase the estimate, with the existing inputs and coefficient unchanged:
A neutral predicate with selectivity one must leave the result unchanged, as must reordering the inputs. For example, selectivities$0.1$ and $0.2$ allow an estimate between $0.02$ and $0.1$ .
Applying this to outer predicates
The outer estimates$q_i$ use statistics after local filtering, so we interpret them as approximations to $P(E_i\mid L)$ . The probability decomposition is:
Therefore, let the proposed overall estimate$S_d$ be:
Damping combines the outer estimates within the locally filtered population. The local selectivity remains a separate multiplier. For$k\ge1$ :
Without outer predicates, return$s_L$ . With one outer predicate, return $s_Lq_1$ for every coefficient.
Theoretical counterexample
Suppose local filtering retains an estimated 1,000 of 10,000 rows, so$s_L=0.1$ . Add an outer equality with $D_1=1$ , giving $q_1=1$ . This multiplier excludes no locally qualifying rows, so the combined estimate should remain $0.1$ .
Instead, the current implementation counts two factors and returns:
Adding a conjunct increases the estimated qualifying population from 1,000 to approximately 1,778 rows. Capping the result at one does not prevent this violation.
Even a cap at$s_L$ would be insufficient: with $s_L=0.1$ and $q_1=0.2$ , the current formula returns approximately $0.035556$ , exceeding the conditional-model result $s_Lq_1=0.02$ .
The change would preserve these bounds and honor the configured damping coefficient in an estimate used for index selection.
SQL demonstrations
Create a 10,000-row inner table and a single-row outer table. The bitmap indexes and disabled hash joins encourage ORCA to consider index conditions containing outer references.
The estimates below refer to the value returned by
CFilterStatsProcessor::SelectivityOfPredicate(), which can be inspected in a debugger. They are not necessarily the row estimates shown byEXPLAIN.The generated data has the following properties:
abcz1. Local predicate only
The query returns exactly 1,000 rows, corresponding to a selectivity of$0.1$ . In the debugger, the function returned
0.099999003112316131; the small difference comes from ORCA's normalization of floating-point frequencies.This is the baseline. Damping does not affect this single equality. The calculations below use the idealized value$s_L=0.1$ for clarity.
2. Add a neutral outer predicate
Both
i.zand the single outer row'so.zare zero, so the additional condition excludes no rows:The actual output remains 1,000 rows.
The original formula increases the estimate when a conjunct is added. Instead, the corrected formula should preserve the baseline estimate, as required.
Implementation
Implementation
We propose keeping the local selectivity separate and applying the existing conjunction estimator only to predicates containing outer references.
Combine conditional outer estimates
Let$s_L$ be the estimated local selectivity and $q_i$ the estimated selectivity of outer predicate $E_i$ within the locally filtered population. For $k$ outer predicates and damping coefficient $d$ , the overall estimate is:
where$F_d$ combines the outer estimates. The local filter is not included in this damping step: it has already been estimated, and its output defines the population to which the outer estimates apply.
The implementation preserves the existing individual estimates:$q_i=1/D_i$ for a recognized outer equality with NDV $D_i\ge1$ , and the default selectivity otherwise. Constant
TRUEexpressions are ignored.Instead of multiplying these estimates immediately, the function collects their scale factors$SF_i=1/q_i$ and passes them to
CScaleFactorUtils::CalcScaleFactorCumulativeConj().Reuse the existing conjunction formula
The helper sorts the scale factors in descending order. Equivalently, the outer selectivities are ordered as:
where$q_{(j)}$ is the selectivity at position $j$ after sorting. For $0<d\le1$ and $k\ge1$ , its calculation corresponds to:
The smallest selectivity is preserved. Each remaining contribution is at most one, giving:
At$d=1$ , the result is the ordinary product. With one outer predicate, it is $s_Lq_1$ . With no outer predicates, the helper returns scale factor one and the result remains $s_L$ .
SelectivityOfPredicate()returns the local selectivity divided by the combined outer scale factor. This replaces the old division of the complete product byUse the configured coefficient
The helper will receive the active statistics configuration from
GetStatsConf(). The final aggregation will therefore honoroptimizer_damping_factor_filterinstead of constructing a default configuration with coefficient0.75. This proposal reuses the shared helper without modifying its implementation.Separate follow-up for zero damping
Explicit handling of
optimizer_damping_factor_filter = 0will be covered by a separate proposal and PR. That change will allow zero in the filter configuration assertion and handle it in the shared conjunction helper as maximum overlap:Changes to the assertion and explicit zero-damping handling are outside the scope of this proposal.
Rollout/Adoption Plan
No response
Are you willing to submit a PR?
All reactions