Skip to content

Commit d3e9883

Browse files
committed
sql/schemachanger: execute validation operations in batches for indexes
Previously, when ALTER PRIMARY KEY was issued or multiple indexes were created in a single transaction, we would end up recounting the table for each index. This patch modifies the validation logic to batch counts of indexes together on the same table. Fixes: #156590 Release note (performance improvement): Optimize validation queries during ALTER PRIMARY KEY to avoid counting the primary key multiple times.
1 parent fbe4b69 commit d3e9883

File tree

8 files changed

+100
-57
lines changed

8 files changed

+100
-57
lines changed

pkg/ccl/schemachangerccl/testdata/end_to_end/add_column_multiple_regional_by_row/add_column_multiple_regional_by_row.side_effects

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,8 +1389,7 @@ update progress of schema change job #1: "Pending: Validating index (2 operation
13891389
commit transaction #24
13901390
begin transaction #25
13911391
## PostCommitPhase stage 23 of 23 with 2 ValidationType ops
1392-
validate forward indexes [2] in table #108
1393-
validate forward indexes [4] in table #108
1392+
validate forward indexes [2 4] in table #108
13941393
commit transaction #25
13951394
begin transaction #26
13961395
## PostCommitNonRevertiblePhase stage 1 of 5 with 33 MutationType ops

pkg/ccl/schemachangerccl/testdata/end_to_end/alter_table_alter_primary_key_rbr/alter_table_alter_primary_key_rbr.side_effects

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,9 +968,8 @@ update progress of schema change job #1: "Pending: Validating NOT NULL constrain
968968
commit transaction #16
969969
begin transaction #17
970970
## PostCommitPhase stage 15 of 24 with 3 ValidationType ops
971-
validate forward indexes [10] in table #108
971+
validate forward indexes [10 4] in table #108
972972
validate CHECK constraint crdb_internal_k_shard_16_auto_not_null in table #108
973-
validate forward indexes [4] in table #108
974973
commit transaction #17
975974
begin transaction #18
976975
## PostCommitPhase stage 16 of 24 with 27 MutationType ops

pkg/sql/schemachanger/scexec/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ go_library(
3939
"//pkg/sql/sem/catid",
4040
"//pkg/sql/sem/idxtype",
4141
"//pkg/sql/sessiondata",
42+
"//pkg/util/buildutil",
4243
"//pkg/util/ctxgroup",
4344
"//pkg/util/hlc",
4445
"//pkg/util/intsets",

pkg/sql/schemachanger/scexec/exec_validation.go

Lines changed: 93 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,32 @@ import (
99
"context"
1010

1111
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
12+
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
1213
"github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scerrors"
1314
"github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scop"
1415
"github.com/cockroachdb/cockroach/pkg/sql/sem/idxtype"
1516
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
17+
"github.com/cockroachdb/cockroach/pkg/util/buildutil"
1618
"github.com/cockroachdb/errors"
1719
)
1820

19-
func executeValidateIndex(ctx context.Context, deps Dependencies, op *scop.ValidateIndex) error {
20-
descs, err := deps.Catalog().MustReadImmutableDescriptors(ctx, op.TableID)
21+
func executeValidateIndexes(
22+
ctx context.Context, deps Dependencies, ops []*scop.ValidateIndex,
23+
) error {
24+
// Nothing to validate.
25+
if len(ops) == 0 {
26+
return nil
27+
}
28+
// Validate all validation operations are against the same table.
29+
if buildutil.CrdbTestBuild {
30+
for _, op := range ops {
31+
if op.TableID != ops[0].TableID {
32+
return errors.AssertionFailedf("all validation operations must be against the same table")
33+
}
34+
}
35+
}
36+
37+
descs, err := deps.Catalog().MustReadImmutableDescriptors(ctx, ops[0].TableID)
2138
if err != nil {
2239
return err
2340
}
@@ -26,25 +43,35 @@ func executeValidateIndex(ctx context.Context, deps Dependencies, op *scop.Valid
2643
if !ok {
2744
return catalog.WrapTableDescRefErr(desc.GetID(), catalog.NewDescriptorTypeError(desc))
2845
}
29-
index, err := catalog.MustFindIndexByID(table, op.IndexID)
30-
if err != nil {
31-
return err
46+
indexTypes := make(map[idxtype.T][]catalog.Index)
47+
for _, validateIndex := range ops {
48+
index, err := catalog.MustFindIndexByID(table, validateIndex.IndexID)
49+
if err != nil {
50+
return err
51+
}
52+
indexTypes[index.GetType()] = append(indexTypes[index.GetType()], index)
3253
}
3354
// Execute the validation operation as a node user.
3455
execOverride := sessiondata.NodeUserSessionDataOverride
35-
switch index.GetType() {
36-
case idxtype.FORWARD:
37-
err = deps.Validator().ValidateForwardIndexes(ctx, deps.TransactionalJobRegistry().CurrentJob(), table, []catalog.Index{index}, execOverride)
38-
case idxtype.INVERTED:
39-
err = deps.Validator().ValidateInvertedIndexes(ctx, deps.TransactionalJobRegistry().CurrentJob(), table, []catalog.Index{index}, execOverride)
40-
case idxtype.VECTOR:
41-
// TODO(drewk): consider whether we can perform useful validation for
42-
// vector indexes.
43-
default:
44-
return errors.AssertionFailedf("unexpected index type %v", index.GetType())
45-
}
46-
if err != nil {
47-
return scerrors.SchemaChangerUserError(err)
56+
// Execute each type of index together, so that the table counts are only
57+
// fetched once.
58+
for typ, indexes := range indexTypes {
59+
var err error
60+
switch typ {
61+
case idxtype.FORWARD:
62+
err = deps.Validator().ValidateForwardIndexes(ctx, deps.TransactionalJobRegistry().CurrentJob(), table, indexes, execOverride)
63+
case idxtype.INVERTED:
64+
err = deps.Validator().ValidateInvertedIndexes(ctx, deps.TransactionalJobRegistry().CurrentJob(), table, indexes, execOverride)
65+
case idxtype.VECTOR:
66+
// TODO(drewk): consider whether we can perform useful validation for
67+
// vector indexes.
68+
continue
69+
default:
70+
return errors.AssertionFailedf("unexpected index type %v", typ)
71+
}
72+
if err != nil {
73+
return scerrors.SchemaChangerUserError(err)
74+
}
4875
}
4976
return nil
5077
}
@@ -105,40 +132,64 @@ func executeValidateColumnNotNull(
105132
}
106133

107134
func executeValidationOps(ctx context.Context, deps Dependencies, ops []scop.Op) (err error) {
135+
v := makeValidationAccumulator(ops)
136+
return v.validate(ctx, deps)
137+
}
138+
139+
// validationAccumulator batches validation operations on a per-table basis, so
140+
// that index validations can be batched together.
141+
type validationAccumulator struct {
142+
indexes map[descpb.ID][]*scop.ValidateIndex
143+
constraints map[descpb.ID][]*scop.ValidateConstraint
144+
notNulls map[descpb.ID][]*scop.ValidateColumnNotNull
145+
}
146+
147+
// makeValidationAccumulator creates a validationAccumulator from a list of
148+
// validation operations.
149+
func makeValidationAccumulator(ops []scop.Op) validationAccumulator {
150+
v := validationAccumulator{
151+
indexes: make(map[descpb.ID][]*scop.ValidateIndex),
152+
constraints: make(map[descpb.ID][]*scop.ValidateConstraint),
153+
notNulls: make(map[descpb.ID][]*scop.ValidateColumnNotNull),
154+
}
108155
for _, op := range ops {
109-
if err = executeValidationOp(ctx, deps, op); err != nil {
110-
return err
156+
switch op := op.(type) {
157+
case *scop.ValidateIndex:
158+
v.indexes[op.TableID] = append(v.indexes[op.TableID], op)
159+
case *scop.ValidateConstraint:
160+
v.constraints[op.TableID] = append(v.constraints[op.TableID], op)
161+
case *scop.ValidateColumnNotNull:
162+
v.notNulls[op.TableID] = append(v.notNulls[op.TableID], op)
163+
default:
164+
panic("unimplemented")
111165
}
112166
}
113-
return nil
167+
return v
114168
}
115169

116-
func executeValidationOp(ctx context.Context, deps Dependencies, op scop.Op) (err error) {
117-
switch op := op.(type) {
118-
case *scop.ValidateIndex:
119-
if err = executeValidateIndex(ctx, deps, op); err != nil {
120-
if !scerrors.HasSchemaChangerUserError(err) {
121-
return errors.Wrapf(err, "%T: %v", op, op)
122-
}
123-
return err
170+
// validate executes all validation operations in the accumulator.
171+
func (v validationAccumulator) validate(ctx context.Context, deps Dependencies) error {
172+
// Batch all index operations per table for efficient execution.
173+
for _, tableIndexes := range v.indexes {
174+
if err := executeValidateIndexes(ctx, deps, tableIndexes); err != nil {
175+
// Error is wrapped with the operation inside the validation method.
176+
return errors.Wrapf(err, "%T: %v", tableIndexes, tableIndexes)
124177
}
125-
case *scop.ValidateConstraint:
126-
if err = executeValidateConstraint(ctx, deps, op); err != nil {
127-
if !scerrors.HasSchemaChangerUserError(err) {
128-
return errors.Wrapf(err, "%T: %v", op, op)
178+
}
179+
// These operations do not support any type of batching.
180+
for _, tableNotNulls := range v.notNulls {
181+
for _, notNull := range tableNotNulls {
182+
if err := executeValidateColumnNotNull(ctx, deps, notNull); err != nil {
183+
return errors.Wrapf(err, "%T: %v", notNull, notNull)
129184
}
130-
return err
131185
}
132-
case *scop.ValidateColumnNotNull:
133-
if err = executeValidateColumnNotNull(ctx, deps, op); err != nil {
134-
if !scerrors.HasSchemaChangerUserError(err) {
135-
return errors.Wrapf(err, "%T: %v", op, op)
186+
}
187+
for _, tableConstraints := range v.constraints {
188+
for _, constraint := range tableConstraints {
189+
if err := executeValidateConstraint(ctx, deps, constraint); err != nil {
190+
return errors.Wrapf(err, "%T: %v", constraint, constraint)
136191
}
137-
return err
138192
}
139-
140-
default:
141-
panic("unimplemented")
142193
}
143194
return nil
144195
}

pkg/sql/schemachanger/testdata/end_to_end/alter_table_add_primary_key_drop_rowid_with_secondary_idx/alter_table_add_primary_key_drop_rowid_with_secondary_idx.side_effects

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -887,9 +887,7 @@ update progress of schema change job #1: "Pending: Validating index (3 operation
887887
commit transaction #8
888888
begin transaction #9
889889
## PostCommitPhase stage 7 of 16 with 3 ValidationType ops
890-
validate forward indexes [10] in table #104
891-
validate forward indexes [6] in table #104
892-
validate forward indexes [8] in table #104
890+
validate forward indexes [10 6 8] in table #104
893891
commit transaction #9
894892
begin transaction #10
895893
## PostCommitPhase stage 8 of 16 with 23 MutationType ops

pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_primary_key_drop_rowid_with_idx/alter_table_alter_primary_key_drop_rowid_with_idx.side_effects

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,7 @@ update progress of schema change job #1: "Pending: Validating index (2 operation
814814
commit transaction #16
815815
begin transaction #17
816816
## PostCommitPhase stage 15 of 23 with 2 ValidationType ops
817-
validate forward indexes [8] in table #104
818-
validate forward indexes [4] in table #104
817+
validate forward indexes [8 4] in table #104
819818
commit transaction #17
820819
begin transaction #18
821820
## PostCommitPhase stage 16 of 23 with 17 MutationType ops

pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_primary_key_using_hash/alter_table_alter_primary_key_using_hash.side_effects

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,9 +616,8 @@ update progress of schema change job #1: "Pending: Validating NOT NULL constrain
616616
commit transaction #8
617617
begin transaction #9
618618
## PostCommitPhase stage 7 of 16 with 3 ValidationType ops
619-
validate forward indexes [8] in table #104
619+
validate forward indexes [8 4] in table #104
620620
validate CHECK constraint crdb_internal_j_shard_3_auto_not_null in table #104
621-
validate forward indexes [4] in table #104
622621
commit transaction #9
623622
begin transaction #10
624623
## PostCommitPhase stage 8 of 16 with 20 MutationType ops

pkg/sql/schemachanger/testdata/end_to_end/alter_table_alter_primary_key_vanilla/alter_table_alter_primary_key_vanilla.side_effects

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -739,10 +739,7 @@ update progress of schema change job #1: "Pending: Validating index (4 operation
739739
commit transaction #8
740740
begin transaction #9
741741
## PostCommitPhase stage 7 of 15 with 4 ValidationType ops
742-
validate forward indexes [16] in table #104
743-
validate forward indexes [8] in table #104
744-
validate forward indexes [10] in table #104
745-
validate forward indexes [12] in table #104
742+
validate forward indexes [16 8 10 12] in table #104
746743
commit transaction #9
747744
begin transaction #10
748745
## PostCommitPhase stage 8 of 15 with 23 MutationType ops

0 commit comments

Comments
 (0)