Skip to content

Commit 3fa8423

Browse files
committed
opt: eliminate barrier expressions at the root
`BarrierExpr`s are now eliminated at the root of the expression tree. These barriers are typically pulled up the expression tree by normalization rules. At the root, they are useless, as their purpose is an optimization barrier which prevents filters from being pushed into their input. These barriers also prevented the placeholder-fast path from applying, incurring extra overhead for queries on RLS tables. Barrier elimination occurs in `optbuilder` when building the canonical plan. It cannot be codified as a normalization rule because the `Construct...` functions have no concept of a root expression when they are invoked. The tree is built bottom-up so the root expression is only known by callers, when all other expressions have been built. Barrier expressions are never added nor pulled up the tree during exploration, so removing a barrier at the root in the canonical plan should be sufficient in eliminating a barriers at the root in all optimized plans. Fixes #149694 Release note (performance improvement): Some types of simple queries that query a table with RLS enabled are now more efficiently executed.
1 parent 339120e commit 3fa8423

File tree

7 files changed

+285
-220
lines changed

7 files changed

+285
-220
lines changed

pkg/sql/opt/norm/testdata/rules/barrier

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ CREATE TABLE xy (x INT PRIMARY KEY, y INT);
66
# EliminateRedundantBarrier
77
# --------------------------------------------------
88

9-
# TODO(sql-queries): for simplicity, we should eliminate the barrier expression
10-
# at the root in this case. It serves no purpose because the filters were able
11-
# to permeate it.
9+
# NOTE: Barriers at the root are eliminated by optbuilder, not a normalization
10+
# rule. exprnorm bypasses optbuilder, so the root barrier remains in the output
11+
# of this test case.
1212
exprnorm expect=EliminateRedundantBarrier
1313
(Barrier
1414
(Barrier

pkg/sql/opt/norm/testdata/rules/join

Lines changed: 142 additions & 167 deletions
Large diffs are not rendered by default.

pkg/sql/opt/norm/testdata/rules/project

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,19 +2055,17 @@ SET ROLE alice;
20552055
norm expect=PushLeakproofProjectionsIntoPermeableBarrier
20562056
SELECT CASE WHEN y = 20 THEN 10 ELSE 0 END FROM rls
20572057
----
2058-
barrier
2058+
project
20592059
├── columns: case:6
2060-
└── project
2061-
├── columns: case:6
2062-
├── select
2063-
│ ├── columns: y:2 alice_has_access:3!null
2064-
│ ├── fd: ()-->(3)
2065-
│ ├── scan rls
2066-
│ │ └── columns: y:2 alice_has_access:3
2067-
│ └── filters
2068-
│ └── alice_has_access:3 [outer=(3), constraints=(/3: [/true - /true]; tight), fd=()-->(3)]
2069-
└── projections
2070-
└── CASE WHEN y:2 = 20 THEN 10 ELSE 0 END [as=case:6, outer=(2)]
2060+
├── select
2061+
│ ├── columns: y:2 alice_has_access:3!null
2062+
│ ├── fd: ()-->(3)
2063+
│ ├── scan rls
2064+
│ │ └── columns: y:2 alice_has_access:3
2065+
│ └── filters
2066+
│ └── alice_has_access:3 [outer=(3), constraints=(/3: [/true - /true]; tight), fd=()-->(3)]
2067+
└── projections
2068+
└── CASE WHEN y:2 = 20 THEN 10 ELSE 0 END [as=case:6, outer=(2)]
20712069

20722070
# Only some expressions in projection are leakproof
20732071
norm expect-not=PushLeakproofProjectionsIntoPermeableBarrier
@@ -2122,23 +2120,19 @@ project
21222120
norm expect=PushLeakproofProjectionsIntoPermeableBarrier
21232121
SELECT x, y, CASE WHEN y = 20 THEN 10 ELSE 0 END FROM rls
21242122
----
2125-
barrier
2123+
project
21262124
├── columns: x:1!null y:2 case:6
21272125
├── key: (1)
21282126
├── fd: (1)-->(2), (2)-->(6)
2129-
└── project
2130-
├── columns: case:6 x:1!null y:2
2131-
├── key: (1)
2132-
├── fd: (1)-->(2), (2)-->(6)
2133-
├── select
2134-
│ ├── columns: x:1!null y:2 alice_has_access:3!null
2135-
│ ├── key: (1)
2136-
│ ├── fd: ()-->(3), (1)-->(2)
2137-
│ ├── scan rls
2138-
│ │ ├── columns: x:1!null y:2 alice_has_access:3
2139-
│ │ ├── key: (1)
2140-
│ │ └── fd: (1)-->(2,3)
2141-
│ └── filters
2142-
│ └── alice_has_access:3 [outer=(3), constraints=(/3: [/true - /true]; tight), fd=()-->(3)]
2143-
└── projections
2144-
└── CASE WHEN y:2 = 20 THEN 10 ELSE 0 END [as=case:6, outer=(2)]
2127+
├── select
2128+
│ ├── columns: x:1!null y:2 alice_has_access:3!null
2129+
│ ├── key: (1)
2130+
│ ├── fd: ()-->(3), (1)-->(2)
2131+
│ ├── scan rls
2132+
│ │ ├── columns: x:1!null y:2 alice_has_access:3
2133+
│ │ ├── key: (1)
2134+
│ │ └── fd: (1)-->(2,3)
2135+
│ └── filters
2136+
│ └── alice_has_access:3 [outer=(3), constraints=(/3: [/true - /true]; tight), fd=()-->(3)]
2137+
└── projections
2138+
└── CASE WHEN y:2 = 20 THEN 10 ELSE 0 END [as=case:6, outer=(2)]

pkg/sql/opt/norm/testdata/rules/select

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,21 +2689,17 @@ project
26892689
norm expect=PushLeakproofFiltersIntoPermeableBarrier
26902690
SELECT * FROM rls WHERE y = 20;
26912691
----
2692-
barrier
2692+
select
26932693
├── columns: x:1!null y:2!null alice_has_access:3!null
26942694
├── key: (1)
26952695
├── fd: ()-->(2,3)
2696-
└── select
2697-
├── columns: x:1!null y:2!null alice_has_access:3!null
2698-
├── key: (1)
2699-
├── fd: ()-->(2,3)
2700-
├── scan rls
2701-
│ ├── columns: x:1!null y:2 alice_has_access:3
2702-
│ ├── key: (1)
2703-
│ └── fd: (1)-->(2,3)
2704-
└── filters
2705-
├── alice_has_access:3 [outer=(3), constraints=(/3: [/true - /true]; tight), fd=()-->(3)]
2706-
└── y:2 = 20 [outer=(2), constraints=(/2: [/20 - /20]; tight), fd=()-->(2)]
2696+
├── scan rls
2697+
│ ├── columns: x:1!null y:2 alice_has_access:3
2698+
│ ├── key: (1)
2699+
│ └── fd: (1)-->(2,3)
2700+
└── filters
2701+
├── alice_has_access:3 [outer=(3), constraints=(/3: [/true - /true]; tight), fd=()-->(3)]
2702+
└── y:2 = 20 [outer=(2), constraints=(/2: [/20 - /20]; tight), fd=()-->(2)]
27072703

27082704
# --------------------------------------------------
27092705
# NormalizeLikeAny

pkg/sql/opt/optbuilder/builder.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/cockroachdb/cockroach/pkg/sql/delegate"
1717
"github.com/cockroachdb/cockroach/pkg/sql/opt"
1818
"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
19+
"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
1920
"github.com/cockroachdb/cockroach/pkg/sql/opt/norm"
2021
"github.com/cockroachdb/cockroach/pkg/sql/opt/optgen/exprgen"
2122
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
@@ -299,7 +300,12 @@ func (b *Builder) buildStmtAtRoot(stmt tree.Statement, desiredTypes []*types.T)
299300
// A "root" statement cannot refer to anything from an enclosing query, so
300301
// we always start with an empty scope.
301302
inScope := b.allocScope()
302-
return b.buildStmtAtRootWithScope(stmt, desiredTypes, inScope)
303+
outScope = b.buildStmtAtRootWithScope(stmt, desiredTypes, inScope)
304+
if b, ok := outScope.expr.(*memo.BarrierExpr); ok {
305+
// Eliminate a barrier that has been pulled up to the root of the tree.
306+
outScope.expr = b.Input
307+
}
308+
return outScope
303309
}
304310

305311
// buildStmtAtRootWithScope is similar to buildStmtAtRoot, but allows a scope to

pkg/sql/opt/optbuilder/testdata/row_level_security

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,15 +2110,13 @@ CREATE POLICY p1 ON ob USING (user_has_access);
21102110
norm
21112111
SELECT * FROM ob WHERE y = 20;
21122112
----
2113-
barrier
2113+
select
21142114
├── columns: x:1!null y:2!null user_has_access:3!null
2115-
└── select
2116-
├── columns: x:1!null y:2!null user_has_access:3!null
2117-
├── scan ob
2118-
│ └── columns: x:1!null y:2 user_has_access:3
2119-
└── filters
2120-
├── user_has_access:3
2121-
└── y:2 = 20
2115+
├── scan ob
2116+
│ └── columns: x:1!null y:2 user_has_access:3
2117+
└── filters
2118+
├── user_has_access:3
2119+
└── y:2 = 20
21222120

21232121
# Barrier needed. Try to expose with a division by zero error.
21242122
norm
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
exec-ddl
2+
CREATE TABLE t (
3+
a INT PRIMARY KEY,
4+
b INT,
5+
c INT,
6+
d INT,
7+
INDEX (b),
8+
INDEX (d, c)
9+
)
10+
----
11+
12+
# The fast path is conditional on having a small estimated row count. Inject
13+
# statistics so that we don't have to worry about this aspect in tests.
14+
exec-ddl
15+
ALTER TABLE t INJECT STATISTICS '[
16+
{
17+
"columns": ["a"],
18+
"created_at": "2018-05-01 1:00:00.00000+00:00",
19+
"row_count": 10,
20+
"distinct_count": 10
21+
}
22+
]'
23+
----
24+
25+
exec-ddl
26+
CREATE ROLE alice
27+
----
28+
29+
exec-ddl
30+
CREATE ROLE bob
31+
----
32+
33+
exec-ddl
34+
CREATE POLICY select_policy_alice
35+
ON t
36+
FOR SELECT
37+
TO alice
38+
USING (true)
39+
----
40+
41+
exec-ddl
42+
CREATE POLICY select_policy_bob
43+
ON t
44+
FOR SELECT
45+
TO bob
46+
USING (d = 0)
47+
----
48+
49+
exec-ddl
50+
ALTER TABLE t ENABLE ROW LEVEL SECURITY
51+
----
52+
53+
exec-ddl
54+
SET ROLE alice
55+
----
56+
57+
placeholder-fast-path
58+
SELECT a FROM t WHERE b = $1
59+
----
60+
placeholder-scan t@t_b_idx
61+
├── columns: a:1!null
62+
├── has-placeholder
63+
├── stats: [rows=9.9]
64+
├── key: (1)
65+
└── span
66+
└── $1
67+
68+
# The index on (d, c) cannot be used because d is not constrained by the query
69+
# nor the policy.
70+
placeholder-fast-path
71+
SELECT a FROM t WHERE c = $1
72+
----
73+
no fast path
74+
75+
exec-ddl
76+
SET ROLE bob
77+
----
78+
79+
# The fast path cannot be used because there is an additional filter on d that
80+
# is not pushed into an index constraint.
81+
placeholder-fast-path
82+
SELECT a FROM t WHERE b = $1
83+
----
84+
no fast path
85+
86+
placeholder-fast-path
87+
SELECT a FROM t WHERE c = $1
88+
----
89+
placeholder-scan t@t_d_c_idx
90+
├── columns: a:1!null
91+
├── has-placeholder
92+
├── stats: [rows=9.801]
93+
├── key: (1)
94+
└── span
95+
├── 0
96+
└── $1

0 commit comments

Comments
 (0)