Skip to content

Commit

Permalink
optbuilder: build insert fast-path uniq checks only if all checks can…
Browse files Browse the repository at this point in the history
… be built

This commit avoids unnecessary processing of insert fast path uniqueness
checks by modifying the optbuilder to avoid building a
`FastPathUniqueChecksExpr` in the Insert expression if one or more
of the required `FastPathUniqueChecksItem`s could not be built.

Epic: CRDB-26290
Informs: #58047

Release note: None
  • Loading branch information
Mark Sirek committed Oct 6, 2023
1 parent 1f78d3b commit 4fba820
Show file tree
Hide file tree
Showing 5 changed files with 795 additions and 893 deletions.
5 changes: 5 additions & 0 deletions pkg/sql/opt/exec/execbuilder/mutation.go
Expand Up @@ -142,6 +142,11 @@ func (b *Builder) tryBuildFastPathInsert(ins *memo.InsertExpr) (_ execPlan, ok b
if !b.allowInsertFastPath {
return execPlan{}, false, nil
}
// If there are unique checks required, there must be the same number of fast
// path unique checks.
if len(ins.UniqueChecks) != len(ins.FastPathUniqueChecks) {
return execPlan{}, false, nil
}

insInput := ins.Input
values, ok := insInput.(*memo.ValuesExpr)
Expand Down
31 changes: 21 additions & 10 deletions pkg/sql/opt/optbuilder/mutation_builder_unique.go
Expand Up @@ -44,6 +44,7 @@ func (mb *mutationBuilder) buildUniqueChecksForInsert() {

h := &mb.uniqueCheckHelper

buildFastPathCheck := true
for i, n := 0, mb.tab.UniqueCount(); i < n; i++ {
// If this constraint is already enforced by an index, we don't need to plan
// a check.
Expand All @@ -58,9 +59,16 @@ func (mb *mutationBuilder) buildUniqueChecksForInsert() {
continue
}
if h.init(mb, i) {
uniqueChecksItem, fastPathUniqueChecksItem := h.buildInsertionCheck(true /* buildFastPathCheck */)
uniqueChecksItem, fastPathUniqueChecksItem := h.buildInsertionCheck(buildFastPathCheck)
if fastPathUniqueChecksItem == nil {
// If we can't build one fast path check, don't build any of them into
// the expression tree.
buildFastPathCheck = false
mb.fastPathUniqueChecks = nil
} else {
mb.fastPathUniqueChecks = append(mb.fastPathUniqueChecks, *fastPathUniqueChecksItem)
}
mb.uniqueChecks = append(mb.uniqueChecks, uniqueChecksItem)
mb.fastPathUniqueChecks = append(mb.fastPathUniqueChecks, fastPathUniqueChecksItem)
}
}
telemetry.Inc(sqltelemetry.UniqueChecksUseCounter)
Expand Down Expand Up @@ -409,10 +417,12 @@ func (h *uniqueCheckHelper) buildFiltersForFastPathCheck(
// buildInsertionCheck creates a unique check for rows which are added to a
// table. The input to the insertion check will be produced from the input to
// the mutation operator. If buildFastPathCheck is true, a fast-path unique
// check for the insert is also built.
// check for the insert is also built. A `UniqueChecksItem` can always be built,
// but if it is not possible to build a `FastPathUniqueChecksItem`, the second
// return value is nil.
func (h *uniqueCheckHelper) buildInsertionCheck(
buildFastPathCheck bool,
) (memo.UniqueChecksItem, memo.FastPathUniqueChecksItem) {
) (memo.UniqueChecksItem, *memo.FastPathUniqueChecksItem) {
f := h.mb.b.factory

// Build a self semi-join, with the new values on the left and the
Expand Down Expand Up @@ -549,12 +559,13 @@ func (h *uniqueCheckHelper) buildInsertionCheck(
newFilters := f.CustomFuncs().RemapScanColsInFilter(scanFilters, &scanExpr.ScanPrivate, newScanPrivate)
uniqueFastPathCheck = f.ConstructSelect(newScanExpr, newFilters)
} else {
uniqueFastPathCheck = f.CustomFuncs().ConstructEmptyValues(opt.ColSet{})
// Don't build a fast-path check if we failed to create a new ScanExpr.
buildFastPathCheck = false
}
} else if buildFastPathCheck {
// Things blow up if a RelExpr is nil, so construct a minimal dummy relation
// that will not be used.
uniqueFastPathCheck = f.CustomFuncs().ConstructEmptyValues(opt.ColSet{})
// Don't build a fast-path check if we failed to build a ScanExpr with
// filters on all unique check columns.
buildFastPathCheck = false
}

uniqueChecks := f.ConstructUniqueChecksItem(project, &memo.UniqueChecksItemPrivate{
Expand All @@ -563,10 +574,10 @@ func (h *uniqueCheckHelper) buildInsertionCheck(
KeyCols: keyCols,
})
if !buildFastPathCheck {
return uniqueChecks, memo.FastPathUniqueChecksItem{}
return uniqueChecks, nil
}
fastPathChecks := f.ConstructFastPathUniqueChecksItem(uniqueFastPathCheck, &memo.FastPathUniqueChecksItemPrivate{ReferencedTableID: h.mb.tabID, CheckOrdinal: h.uniqueOrdinal})
return uniqueChecks, fastPathChecks
return uniqueChecks, &fastPathChecks
}

// buildTableScan builds a Scan of the table. The ordinals of the columns
Expand Down

0 comments on commit 4fba820

Please sign in to comment.