Skip to content

Commit 7fb2898

Browse files
committed
opt/norm: add UseSwapMutation normalization rule
Add a new normalization rule which converts Update and Delete expressions to UpdateSwap and DeleteSwap, respectively. Crucially, this normalization rule also replaces the initial Scan of the mutation with a single-row Values expression, which optimistically provides the complete old row (if it exists and matches the filters). This allows the UpdateSwap and DeleteSwap operators to use CPut to validate the existence of the old row in the same batch as modifying it, changing the mutation statement from 2 RTs to 1 RT. With this normalization rule in place, UpdateSwap and DeleteSwap should be available for use by any qualifying UPDATE and DELETE statements. Fixes: #144503 Fixes: #85328 Release note (performance improvement): Add new `update swap` and `delete swap` operators which allow some UPDATE and DELETE statements to execute in 1 round trip instead of 2 round trips. For now, these operators can be used when: - all columns in the primary index are constrained to a single exact value by the WHERE clause; - only a single row is modified; - there are no FK checks or cascades; - there are no uniqueness checks; - there are no check constraints; - there are no vector indexes modified; - there are no passthrough columns to RETURNING; - there are no triggers; - the table only uses a single column family; - there are no mutation columns or mutation indexes (i.e. the table is not undergoing an ALTER); - there are no columns using composite encoding (e.g. DECIMAL, FLOAT, JSON, etc). We may lift some of these restrictions in future releases.
1 parent 816b8e9 commit 7fb2898

File tree

12 files changed

+2964
-12
lines changed

12 files changed

+2964
-12
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# LogicTest: local
2+
3+
# Test that unique indexes work correctly with swap mutations.
4+
5+
statement ok
6+
CREATE TABLE xyz (
7+
x INT PRIMARY KEY,
8+
y INT,
9+
z INT,
10+
UNIQUE INDEX (y),
11+
FAMILY (x, y, z)
12+
)
13+
14+
statement ok
15+
INSERT INTO xyz VALUES (1, 1, 1), (2, 2, 2)
16+
17+
# This statement should fail with a dupe key error.
18+
19+
statement error duplicate key value violates unique constraint "xyz_y_key"
20+
UPDATE xyz SET y = 1 WHERE x = 2 AND y = 2 AND z = 2
21+
22+
query III
23+
SELECT * FROM xyz ORDER BY x
24+
----
25+
1 1 1
26+
2 2 2
27+
28+
# This statement should succeed and modify 0 rows, because no rows have z = 3.
29+
30+
statement ok
31+
UPDATE xyz SET y = 1 WHERE x = 2 AND y = 2 AND z = 3
32+
33+
query III
34+
SELECT * FROM xyz ORDER BY x
35+
----
36+
1 1 1
37+
2 2 2
38+
39+
# Test rollback of swap mutations.
40+
41+
statement ok
42+
BEGIN
43+
44+
statement ok
45+
UPDATE xyz SET z = 11 WHERE x = 1 AND y = 1 AND z = 1
46+
47+
query III
48+
SELECT * FROM xyz ORDER BY x
49+
----
50+
1 1 11
51+
2 2 2
52+
53+
statement ok
54+
SAVEPOINT a
55+
56+
statement ok
57+
UPDATE xyz SET z = 12 WHERE x = 2 AND y = 2 AND z = 2
58+
59+
query III
60+
SELECT * FROM xyz ORDER BY x
61+
----
62+
1 1 11
63+
2 2 12
64+
65+
statement ok
66+
ROLLBACK TO a
67+
68+
statement ok
69+
UPDATE xyz SET z = 21 WHERE x = 1 AND y = 1 AND z = 11
70+
71+
query III
72+
SELECT * FROM xyz ORDER BY x
73+
----
74+
1 1 21
75+
2 2 2
76+
77+
statement ok
78+
SAVEPOINT b
79+
80+
# This should do nothing.
81+
82+
statement ok
83+
UPDATE xyz SET z = 31 WHERE x = 1 AND y = 1 AND z = 11
84+
85+
query III
86+
SELECT * FROM xyz ORDER BY x
87+
----
88+
1 1 21
89+
2 2 2
90+
91+
statement ok
92+
ROLLBACK TO b
93+
94+
query III
95+
SELECT * FROM xyz ORDER BY x
96+
----
97+
1 1 21
98+
2 2 2
99+
100+
statement ok
101+
ROLLBACK TO a
102+
103+
query III
104+
SELECT * FROM xyz ORDER BY x
105+
----
106+
1 1 11
107+
2 2 2
108+
109+
# This should do nothing.
110+
111+
statement ok
112+
UPDATE xyz SET z = 31 WHERE x = 1 AND y = 1 AND z = 21
113+
114+
query III
115+
SELECT * FROM xyz ORDER BY x
116+
----
117+
1 1 11
118+
2 2 2
119+
120+
statement ok
121+
COMMIT
122+
123+
query III
124+
SELECT * FROM xyz ORDER BY x
125+
----
126+
1 1 11
127+
2 2 2

pkg/sql/logictest/tests/local/generated_test.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/opt/column_meta.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,25 @@ func (ocl OptionalColList) ToSet() ColSet {
163163
return r
164164
}
165165

166+
// CopyAndMaybeRemapColumns copies this OptionalColList, remapping any columns
167+
// present in the provided ColMap.
168+
func (ocl OptionalColList) CopyAndMaybeRemapColumns(m ColMap) (res OptionalColList) {
169+
if len(ocl) == 0 {
170+
return nil
171+
}
172+
res = make(OptionalColList, len(ocl))
173+
for i, col := range ocl {
174+
if col != 0 {
175+
if val, ok := m.Get(int(col)); ok {
176+
res[i] = ColumnID(val)
177+
} else {
178+
res[i] = col
179+
}
180+
}
181+
}
182+
return res
183+
}
184+
166185
// ColumnMeta stores information about one of the columns stored in the
167186
// metadata.
168187
type ColumnMeta struct {

pkg/sql/opt/exec/execbuilder/testdata/delete

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ vectorized: true
221221

222222
# Tracing tests for fast delete.
223223
statement ok
224-
CREATE TABLE a (a INT PRIMARY KEY)
224+
CREATE TABLE a (a DECIMAL PRIMARY KEY)
225225

226226
# Delete range operates in chunks of 600 (defined by row.TableTruncateChunkSize).
227227
statement ok
@@ -427,28 +427,28 @@ distribution: local
427427
vectorized: true
428428
·
429429
• render
430-
│ columns: (a int, b int, "?column?" unknown)
430+
│ columns: (a decimal, b int, "?column?" unknown)
431431
│ render ?column?: (NULL)[unknown]
432-
│ render a: (a)[int]
432+
│ render a: (a)[decimal]
433433
│ render b: (b)[int]
434434
435435
└── • delete
436-
│ columns: (a int, b int)
436+
│ columns: (a decimal, b int)
437437
│ estimated row count: 1,000 (missing stats)
438438
│ from: a
439439
│ auto commit
440440
441441
└── • distinct
442-
│ columns: (a int, b int)
442+
│ columns: (a decimal, b int)
443443
│ estimated row count: 1,000 (missing stats)
444444
│ distinct on: a
445445
446446
└── • cross join (inner)
447-
│ columns: (a int, b int)
447+
│ columns: (a decimal, b int)
448448
│ estimated row count: 333,333 (missing stats)
449449
450450
├── • scan
451-
│ columns: (a int)
451+
│ columns: (a decimal)
452452
│ estimated row count: 1,000 (missing stats)
453453
│ table: a@a_pkey
454454
│ spans: FULL SCAN

0 commit comments

Comments
 (0)