Skip to content

Commit d9220e9

Browse files
committed
sql: optimize SHOW CREATE TABLE performance with many schema objects
Previously, SHOW CREATE TABLE queried the crdb_internal.zones table to extract the zone configuration. This could be slow with a large number of objects because the subquery needed to scan the entirety of crdb_internal.zones, which would do one round-trip per zone config (to fetch descriptors). This patch optimizes crdb_internal.zones to fetch all required descriptors in a single request, instead of performing a round trip for each descriptor. Additionally, this patch adds a new BenchmarkORMQueries test in the rttanalysisccl package, configured for multi-region testing. Fixes: #141827 Release note (bug fix): Improve slow SHOW CREATE TABLE on multi-region databases with large number of objects
1 parent 094779f commit d9220e9

File tree

3 files changed

+94
-9
lines changed

3 files changed

+94
-9
lines changed

pkg/ccl/benchccl/rttanalysisccl/multi_region_bench_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ package rttanalysisccl
77

88
import (
99
gosql "database/sql"
10+
"fmt"
1011
"net/url"
12+
"strings"
1113
"testing"
1214

1315
"github.com/cockroachdb/cockroach/pkg/base"
@@ -69,6 +71,37 @@ CREATE TABLE test42 (p int) LOCALITY REGIONAL BY TABLE IN "us-east2";
6971
`
7072
)
7173

74+
// multipleTableFixtures creates multiple tables with different localities.
75+
func multipleTableFixtures(n int) string {
76+
b := strings.Builder{}
77+
78+
b.WriteString(`CREATE DATABASE test PRIMARY REGION "us-east1" REGIONS "us-east1", "us-east2", "us-east3";
79+
USE test;`)
80+
b.WriteString("BEGIN;\n")
81+
b.WriteString("SET LOCAL autocommit_before_ddl = false;\n")
82+
for i := 0; i < n; i++ {
83+
b.WriteString(fmt.Sprintf("CREATE TABLE test%d (p int)", i))
84+
85+
locality := i % 5
86+
87+
switch locality {
88+
case 0:
89+
b.WriteString(" LOCALITY GLOBAL")
90+
case 1:
91+
b.WriteString(" LOCALITY REGIONAL BY ROW")
92+
case 2:
93+
b.WriteString(" LOCALITY REGIONAL BY TABLE IN \"us-east1\"")
94+
case 3:
95+
b.WriteString(" LOCALITY REGIONAL BY TABLE IN \"us-east2\"")
96+
case 4:
97+
b.WriteString(" LOCALITY REGIONAL BY TABLE IN \"us-east3\"")
98+
}
99+
b.WriteString(";\n")
100+
}
101+
b.WriteString("COMMIT;\n")
102+
return b.String()
103+
}
104+
72105
func BenchmarkAlterRegions(b *testing.B) { reg.Run(b) }
73106
func init() {
74107
reg.Register("AlterRegions", []rttanalysis.RoundTripBenchTestCase{
@@ -238,3 +271,28 @@ CREATE TABLE test (p int) LOCALITY REGIONAL BY ROW;
238271
},
239272
})
240273
}
274+
275+
func BenchmarkVirtualTableQueries(b *testing.B) { reg.Run(b) }
276+
func init() {
277+
reg.Register("VirtualTableQueries", []rttanalysis.RoundTripBenchTestCase{
278+
{
279+
Name: "select from crdb_internal.zones (10 tables)",
280+
Setup: multipleTableFixtures(10),
281+
Stmt: `select * from crdb_internal.zones`,
282+
Reset: "DROP DATABASE test",
283+
},
284+
{
285+
Name: "select from crdb_internal.zones (50 tables)",
286+
Setup: multipleTableFixtures(50),
287+
Stmt: `select * from crdb_internal.zones`,
288+
Reset: "DROP DATABASE test",
289+
},
290+
291+
{
292+
Name: "select from crdb_internal.zones (100 tables)",
293+
Setup: multipleTableFixtures(100),
294+
Stmt: `select * from crdb_internal.zones`,
295+
Reset: "DROP DATABASE test",
296+
},
297+
})
298+
}

pkg/ccl/benchccl/rttanalysisccl/testdata/benchmark_expectations

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ exp,benchmark
1717
10,AlterTableLocality/alter_from_rbr_to_regional_by_table
1818
13,AlterTableLocality/alter_from_regional_by_table_to_global
1919
18,AlterTableLocality/alter_from_regional_by_table_to_rbr
20+
10,VirtualTableQueries/select_from_crdb_internal.zones_(100_tables)
21+
10,VirtualTableQueries/select_from_crdb_internal.zones_(10_tables)
22+
10,VirtualTableQueries/select_from_crdb_internal.zones_(50_tables)

pkg/sql/crdb_internal.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5026,6 +5026,33 @@ CREATE TABLE crdb_internal.zones (
50265026
return err
50275027
}
50285028
values := make(tree.Datums, len(showZoneConfigColumns))
5029+
descIDs := catalog.DescriptorIDSet{}
5030+
for _, r := range rows {
5031+
id := uint32(tree.MustBeDInt(r[0]))
5032+
zs, err := zonepb.ZoneSpecifierFromID(id, resolveID)
5033+
if err != nil {
5034+
// We can have valid zoneSpecifiers whose table/database has been
5035+
// deleted because zoneSpecifiers are collected asynchronously.
5036+
// In this case, just don't show the zoneSpecifier in the
5037+
// output of the table.
5038+
continue
5039+
}
5040+
if zs.TableOrIndex.Table.Object() == "" && zs.Database == "" {
5041+
continue
5042+
}
5043+
descIDs.Add(descpb.ID(id))
5044+
}
5045+
// Fetch all of the descriptors needed for format the zone configuration
5046+
// information.
5047+
zcDescMap := make(map[catid.DescID]catalog.Descriptor)
5048+
zcDescs, err := p.Descriptors().ByIDWithoutLeased(p.Txn()).Get().Descs(ctx, descIDs.Ordered())
5049+
if err != nil {
5050+
return err
5051+
}
5052+
for _, desc := range zcDescs {
5053+
zcDescMap[desc.GetID()] = desc
5054+
}
5055+
50295056
for _, r := range rows {
50305057
id := uint32(tree.MustBeDInt(r[0]))
50315058

@@ -5058,26 +5085,23 @@ CREATE TABLE crdb_internal.zones (
50585085

50595086
var table catalog.TableDescriptor
50605087
if zs.Database != "" {
5061-
database, err := p.Descriptors().ByIDWithoutLeased(p.txn).Get().Database(ctx, descpb.ID(id))
5062-
if err != nil {
5063-
return err
5064-
}
5088+
database := zcDescMap[catid.DescID(id)]
50655089
if ok, err := p.HasAnyPrivilege(ctx, database); err != nil {
50665090
return err
50675091
} else if !ok {
50685092
continue
50695093
}
50705094
} else if zoneSpecifier.TableOrIndex.Table.ObjectName != "" {
5071-
tableEntry, err := p.Descriptors().ByIDWithoutLeased(p.txn).Get().Table(ctx, descpb.ID(id))
5072-
if err != nil {
5073-
return err
5074-
}
5095+
tableEntry := zcDescMap[catid.DescID(id)]
50755096
if ok, err := p.HasAnyPrivilege(ctx, tableEntry); err != nil {
50765097
return err
50775098
} else if !ok {
50785099
continue
50795100
}
5080-
table = tableEntry
5101+
table, err = catalog.AsTableDescriptor(tableEntry)
5102+
if err != nil {
5103+
return err
5104+
}
50815105
}
50825106

50835107
// Write down information about the zone in the table.

0 commit comments

Comments
 (0)