Skip to content

Commit

Permalink
opt: prune unnecessary columns in uniqueness checks
Browse files Browse the repository at this point in the history
Projects now wrap semi-joins of unique checks which project a single
column of the unique constraint. This allows normalization rules to
prune unnecessary columns from the expression. The unique check errors
if any rows are produced, regardless of the column types or values. A
column from the unique constraint is projected to ensure that an
otherwise unneeded column is not projected (if it were, it would not
be pruned).

Release justification: This is a low-risk change to new functionality,
implicitly partitioned unique indexes.

Release note (performance improvement): The columns fetched for
uniqueness checks of implicitly partitioned unique indexes are now
pruned to only include columns necessary for determining uniqueness.
  • Loading branch information
mgartner committed Mar 2, 2021
1 parent 0f73f30 commit 4939e05
Show file tree
Hide file tree
Showing 6 changed files with 2,397 additions and 2,124 deletions.
560 changes: 300 additions & 260 deletions pkg/sql/opt/exec/execbuilder/testdata/unique

Large diffs are not rendered by default.

392 changes: 202 additions & 190 deletions pkg/sql/opt/norm/testdata/rules/prune_cols

Large diffs are not rendered by default.

24 changes: 22 additions & 2 deletions pkg/sql/opt/optbuilder/mutation_builder_unique.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/cockroach/pkg/util"
"github.com/cockroachdb/errors"
)

// UniquenessChecksForGenRandomUUIDClusterMode controls the cluster setting for
Expand Down Expand Up @@ -151,7 +152,7 @@ func (mb *mutationBuilder) hasUniqueWithoutIndexConstraints() bool {
// constraint are being updated (according to updateColIDs). When the unique
// constraint has a partial predicate, it also returns true if the predicate
// references any of the columns being updated.
func (mb *mutationBuilder) uniqueColsUpdated(uniqueOrdinal int) bool {
func (mb *mutationBuilder) uniqueColsUpdated(uniqueOrdinal cat.UniqueOrdinal) bool {
uc := mb.tab.Unique(uniqueOrdinal)

for i, n := 0, uc.ColumnCount(); i < n; i++ {
Expand Down Expand Up @@ -379,7 +380,26 @@ func (h *uniqueCheckHelper) buildInsertionCheck() memo.UniqueChecksItem {
keyCols = append(keyCols, withScanScope.cols[i].id)
}

return f.ConstructUniqueChecksItem(semiJoin, &memo.UniqueChecksItemPrivate{
// Project only a single column so that normalization rules prune any
// unnecessary columns from the expression. The column type and value does
// not matter. The unique check will fail if there are any rows produced by
// the expression regardless of the values in the row. We project the first
// column in the unique constraint from the WithScan side of the semi-join
// because it will always be needed in the semi-join filter. This guarantees
// that we don't project a column that is otherwise not needed.
uniqueColOrd, ok := h.uniqueOrdinals.Next(0)
if !ok {
panic(errors.AssertionFailedf("uniqueOrdinals cannot be empty"))
}
var passthrough opt.ColSet
passthrough.Add(withScanScope.cols[uniqueColOrd].id)
project := f.ConstructProject(
semiJoin,
nil, /* projections */
passthrough,
)

return f.ConstructUniqueChecksItem(project, &memo.UniqueChecksItemPrivate{
Table: h.mb.tabID,
CheckOrdinal: h.uniqueOrdinal,
KeyCols: keyCols,
Expand Down
Loading

0 comments on commit 4939e05

Please sign in to comment.