Skip to content

Commit 8fefbf9

Browse files
craig[bot]mgartneralyshanjahani-crlrafiss
committed
148465: opt: convert parameterized lookup joins to placeholder scans r=mgartner a=mgartner Parameterized lookup joins, which are used in generic query plans, are now converted to placeholder scans in some cases. These placeholder scans are more efficient because they cater to a narrower set of features than general-purpose lookup joins and because they natively support vectorization. See the new exploration rule for more details. Release note: None 149570: cli: improve debug.zip transaction_contention_events query r=alyshanjahani-crl a=alyshanjahani-crl Improvements to this query were made in #139735, however statement timeouts and memory budget exceeded errors were still occurring. This commit improves the query dump by reducing the result set of the CTEs used in the query. Instead of retrieving all fingerprints from the statement_statistics table and using those in the joins, it first filters by the fingerprints present in the contention event registry. Fixes: #146877 Release note (cli change): Improves the performance of the debug zip query that collects transaction_contention_events data, reducing the chances of "memory budget exceeded" or "query execution canceled due to statement timeout" errors. 149718: roachtest: fix hibernate nightly test r=rafiss a=rafiss The previous version fails during installation with: ``` FAILURE: Build completed with 2 failures. 1: Task failed with an exception. ----------- * What went wrong: Execution failed for task ':hibernate-core:generateGraphParser'. > Failed to load cache entry 7ed5a08bcdbd74c9347d61047c20a896 for task ':hibernate-core:generateGraphParser': Could not load from remote cache: Not in GZIP format * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Get more help at https://help.gradle.org. ============================================================================== 2: Task failed with an exception. ----------- * What went wrong: Execution failed for task ':hibernate-jpamodelgen:jaxb'. > Failed to load cache entry dd3fbbdea5c65a87fb9d720c326dd64b for task ':hibernate-jpamodelgen:jaxb': Could not load from remote cache: Not in GZIP format * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Get more help at https://help.gradle.org. ============================================================================== ``` fixes #149404 fixes #149457 fixes #149455 fixes #149399 fixes #149346 fixes #149393 fixes #149400 fixes #149398 fixes #149406 fixes #149395 Release note: None 149786: roachtest: Fix JSON configuration file for db-console/endpoints r=alyshanjahani-crl a=alyshanjahani-crl A previous PR modified one of the json configuration files for what endpoints to test. It forgot to include a comma... Fixes: #149735, #149732 Release note: None 149793: roachtest: add schemachange/bulkingest variant for ADD COLUMN r=rafiss a=rafiss This patch adds testing for ADD COLUMN backfills. This differs from the CREATE INDEX operation since ADD COLUMN populates an index in order, so it runs more quickly. Measuring this will help us observe improvements in CREATE INDEX. informs #146571 Release note: None Co-authored-by: Marcus Gartner <[email protected]> Co-authored-by: Alyshan Jahani <[email protected]> Co-authored-by: Rafi Shamim <[email protected]>
6 parents 5b8f942 + 62cfc3d + 0f9aa8a + d333a80 + ebfcf4a + 30a2101 commit 8fefbf9

File tree

17 files changed

+1854
-221
lines changed

17 files changed

+1854
-221
lines changed

pkg/cli/zip_table_registry.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -559,26 +559,43 @@ var zipInternalTablesPerCluster = DebugZipTableRegistry{
559559
},
560560
"crdb_internal.transaction_contention_events": {
561561
customQueryUnredacted: `
562-
with fingerprint_queries as (
563-
SELECT distinct fingerprint_id, metadata->> 'query' as query
564-
FROM system.statement_statistics
562+
WITH contention_fingerprints AS (
563+
-- First, extract all relevant fingerprints from contention events
564+
SELECT DISTINCT waiting_stmt_fingerprint_id, blocking_txn_fingerprint_id
565+
FROM crdb_internal.transaction_contention_events
566+
WHERE blocking_txn_fingerprint_id != '\x0000000000000000'
565567
),
566-
transaction_fingerprints as (
567-
SELECT distinct fingerprint_id, transaction_fingerprint_id
568-
FROM system.statement_statistics
569-
),
570-
transaction_queries as (
571-
SELECT tf.transaction_fingerprint_id, array_agg(fq.query) as queries
572-
FROM fingerprint_queries fq
573-
JOIN transaction_fingerprints tf on tf.fingerprint_id = fq.fingerprint_id
574-
GROUP BY tf.transaction_fingerprint_id
568+
fingerprint_queries AS (
569+
-- Only fetch statement data for fingerprints that appear in contention events
570+
SELECT DISTINCT fingerprint_id, metadata->>'query' as query
571+
FROM system.statement_statistics ss
572+
WHERE EXISTS (
573+
SELECT 1 FROM contention_fingerprints cf
574+
WHERE cf.waiting_stmt_fingerprint_id = ss.fingerprint_id
575+
)
576+
),
577+
transaction_fingerprints AS (
578+
-- Only fetch transaction data for fingerprints that appear in contention events
579+
SELECT DISTINCT fingerprint_id, transaction_fingerprint_id
580+
FROM system.statement_statistics ss
581+
WHERE EXISTS (
582+
SELECT 1 FROM contention_fingerprints cf
583+
WHERE cf.waiting_stmt_fingerprint_id = ss.fingerprint_id
584+
)
585+
),
586+
transaction_queries AS (
587+
-- Build transaction queries only for relevant transactions
588+
SELECT tf.transaction_fingerprint_id, array_agg(fq.query) as queries
589+
FROM fingerprint_queries fq
590+
JOIN transaction_fingerprints tf ON tf.fingerprint_id = fq.fingerprint_id
591+
GROUP BY tf.transaction_fingerprint_id
575592
)
576593
SELECT collection_ts,
577594
contention_duration,
578595
waiting_txn_id,
579596
waiting_txn_fingerprint_id,
580597
waiting_stmt_fingerprint_id,
581-
fq.query AS waiting_stmt_query,
598+
fq.query AS waiting_stmt_query,
582599
blocking_txn_id,
583600
blocking_txn_fingerprint_id,
584601
tq.queries AS blocking_txn_queries_unordered,

pkg/cmd/roachtest/tests/db-console/admin_endpoints.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
},
7878
{
7979
"url": "/_admin/v1/rangelog",
80-
"method": "GET"
80+
"method": "GET",
8181
"skip": "https://github.com/cockroachdb/cockroach/pull/148112#issuecomment-2960322577"
8282
},
8383
{

pkg/cmd/roachtest/tests/hibernate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var hibernateReleaseTagRegex = regexp.MustCompile(`^(?P<major>\d+)\.(?P<minor>\d
2323

2424
// WARNING: DO NOT MODIFY the name of the below constant/variable without approval from the docs team.
2525
// This is used by docs automation to produce a list of supported versions for ORM's.
26-
var supportedHibernateTag = "6.6.0"
26+
var supportedHibernateTag = "6.6.20"
2727

2828
type hibernateOptions struct {
2929
testName string

pkg/cmd/roachtest/tests/schemachange.go

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -328,17 +328,32 @@ func makeIndexAddTpccTest(
328328
}
329329
}
330330

331+
// bulkIngestSchemaChangeOp represents the type of schema change operation to
332+
// perform during bulk ingestion testing.
333+
type bulkIngestSchemaChangeOp string
334+
335+
const (
336+
// createIndexOp runs CREATE INDEX, which adds keys in unsorted order.
337+
createIndexOp bulkIngestSchemaChangeOp = "create_index"
338+
// addColumnOp runs ADD COLUMN, which adds keys in sorted order.
339+
addColumnOp bulkIngestSchemaChangeOp = "add_column"
340+
)
341+
331342
func registerSchemaChangeBulkIngest(r registry.Registry) {
332343
// Allow a long running time to account for runs that use a
333344
// cockroach build with runtime assertions enabled.
334-
r.Add(makeSchemaChangeBulkIngestTest(r, 12, 4_000_000_000, 5*time.Hour))
345+
r.Add(makeSchemaChangeBulkIngestTest(r, 12, 4_000_000_000, 5*time.Hour, createIndexOp))
346+
r.Add(makeSchemaChangeBulkIngestTest(r, 12, 4_000_000_000, 5*time.Hour, addColumnOp))
335347
}
336348

337349
func makeSchemaChangeBulkIngestTest(
338-
r registry.Registry, numNodes, numRows int, length time.Duration,
350+
r registry.Registry,
351+
numNodes, numRows int,
352+
length time.Duration,
353+
operation bulkIngestSchemaChangeOp,
339354
) registry.TestSpec {
340355
return registry.TestSpec{
341-
Name: "schemachange/bulkingest",
356+
Name: fmt.Sprintf("schemachange/bulkingest/nodes=%d/rows=%d/%s", numNodes, numRows, operation),
342357
Owner: registry.OwnerSQLFoundations,
343358
Benchmark: true,
344359
Cluster: r.MakeClusterSpec(numNodes, spec.WorkloadNode(), spec.SSD(4)),
@@ -350,26 +365,18 @@ func makeSchemaChangeBulkIngestTest(
350365
// The histogram tracks the total elapsed time for the CREATE INDEX operation.
351366
totalElapsed := histogram.Elapsed
352367

353-
// Calculate the approximate data size for the index.
354-
// The index is on (payload, a) where payload is 40 bytes.
355-
// Approximate size per row for index: 40 bytes (payload) + 8 bytes (a) = 48 bytes
356-
rowsIndexed := int64(numRows)
357-
bytesPerRow := int64(48)
358-
mb := int64(1 << 20)
359-
dataSizeInMB := (rowsIndexed * bytesPerRow) / mb
360-
361-
// Calculate throughput in MB/s per node.
362-
indexDuration := int64(totalElapsed / 1000) // Convert to seconds.
363-
if indexDuration == 0 {
364-
indexDuration = 1 // Avoid division by zero.
368+
// Calculate throughput in rows/sec per node.
369+
schemaChangeDuration := int64(totalElapsed / 1000) // Convert to seconds.
370+
if schemaChangeDuration == 0 {
371+
schemaChangeDuration = 1 // Avoid division by zero.
365372
}
366-
avgRatePerNode := roachtestutil.MetricPoint(float64(dataSizeInMB) / float64(int64(numNodes)*indexDuration))
373+
avgRatePerNode := roachtestutil.MetricPoint(float64(numRows) / float64(int64(numNodes)*schemaChangeDuration))
367374

368375
return roachtestutil.AggregatedPerfMetrics{
369376
{
370377
Name: fmt.Sprintf("%s_throughput", test),
371378
Value: avgRatePerNode,
372-
Unit: "MB/s/node",
379+
Unit: "rows/s/node",
373380
IsHigherBetter: true,
374381
},
375382
}, nil
@@ -427,7 +434,7 @@ func makeSchemaChangeBulkIngestTest(
427434
defer db.Close()
428435

429436
if !c.IsLocal() {
430-
// Wait for the load generator to run for a few minutes before creating the index.
437+
// Wait for the load generator to run for a few minutes before performing the schema change.
431438
sleepInterval := time.Minute * 5
432439
maxSleep := length / 2
433440
if sleepInterval > maxSleep {
@@ -436,16 +443,28 @@ func makeSchemaChangeBulkIngestTest(
436443
time.Sleep(sleepInterval)
437444
}
438445

439-
t.L().Printf("Creating index")
440-
// Tick once before starting the index creation.
446+
// Tick once before starting the schema change.
441447
tickHistogram()
442448
before := timeutil.Now()
443-
if _, err := db.Exec(`CREATE INDEX payload_a ON bulkingest.bulkingest (payload, a)`); err != nil {
449+
450+
var stmt string
451+
switch operation {
452+
case createIndexOp:
453+
t.L().Printf("Creating index")
454+
stmt = `CREATE INDEX payload_a ON bulkingest.bulkingest (payload, a)`
455+
case addColumnOp:
456+
t.L().Printf("Adding column")
457+
stmt = `ALTER TABLE bulkingest.bulkingest ADD COLUMN new_column INT NOT NULL DEFAULT 42`
458+
default:
459+
t.Fatalf("Unknown operation: %s", operation)
460+
}
461+
462+
if _, err := db.Exec(stmt); err != nil {
444463
t.Fatal(err)
445464
}
446-
// Tick once after the index creation to capture the total elapsed time.
465+
// Tick once after the schema change to capture the total elapsed time.
447466
tickHistogram()
448-
t.L().Printf("CREATE INDEX took %v\n", timeutil.Since(before))
467+
t.L().Printf("%s took %v\n", stmt, timeutil.Since(before))
449468
return nil
450469
})
451470

pkg/sql/opt/exec/execbuilder/mutation.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ func shouldApplyImplicitLockingToUpdateOrDeleteInput(
12331233
var toLockIndexes intsets.Fast
12341234
// Try to match the mutation's input expression against the pattern:
12351235
//
1236-
// [Project]* [IndexJoin] (Scan | LookupJoin [LookupJoin] Values)
1236+
// [Project]* [IndexJoin] (Scan | PlaceholderScan | LookupJoin [LookupJoin] Values)
12371237
//
12381238
// The IndexJoin will only be present if the base expression is a Scan, but
12391239
// making it an optional prefix to the LookupJoins makes the logic simpler.
@@ -1247,6 +1247,9 @@ func shouldApplyImplicitLockingToUpdateOrDeleteInput(
12471247
case *memo.ScanExpr:
12481248
toLockIndexes.Add(t.Index)
12491249
toLock = t.Table
1250+
case *memo.PlaceholderScanExpr:
1251+
toLockIndexes.Add(t.Index)
1252+
toLock = t.Table
12501253
case *memo.LookupJoinExpr:
12511254
toLockIndexes.Add(t.Index)
12521255
if innerJoin, ok := t.Input.(*memo.LookupJoinExpr); ok && innerJoin.Table == t.Table {

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

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -500,28 +500,20 @@ quality of service: regular
500500
│ from: t137352
501501
│ auto commit
502502
503-
└── • lookup join
504-
│ sql nodes: <hidden>
505-
│ kv nodes: <hidden>
506-
│ regions: <hidden>
507-
│ actual row count: 0
508-
│ KV time: 0µs
509-
│ KV rows decoded: 0
510-
│ KV bytes read: 0 B
511-
│ KV gRPC calls: 0
512-
│ execution time: 0µs
513-
│ estimated max memory allocated: 0 B
514-
│ table: t137352@t137352_pkey
515-
│ equality: ($1) = (k)
516-
│ equality cols are key
517-
│ locking strength: for update
518-
519-
└── • values
520-
sql nodes: <hidden>
521-
regions: <hidden>
522-
actual row count: 1
523-
execution time: 0µs
524-
size: 1 column, 1 row
503+
└── • scan
504+
sql nodes: <hidden>
505+
kv nodes: <hidden>
506+
regions: <hidden>
507+
actual row count: 0
508+
KV time: 0µs
509+
KV rows decoded: 0
510+
KV bytes read: 0 B
511+
KV gRPC calls: 0
512+
estimated max memory allocated: 0 B
513+
missing stats
514+
table: t137352@t137352_pkey
515+
spans: [/1 - /1]
516+
locking strength: for update
525517

526518
statement ok
527519
INSERT INTO t137352 VALUES (1, 10, 100);

pkg/sql/opt/exec/execbuilder/testdata/update

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,28 +1025,20 @@ quality of service: regular
10251025
10261026
└── • render
10271027
1028-
└── • lookup join
1029-
│ sql nodes: <hidden>
1030-
│ kv nodes: <hidden>
1031-
│ regions: <hidden>
1032-
│ actual row count: 0
1033-
│ KV time: 0µs
1034-
│ KV rows decoded: 0
1035-
│ KV bytes read: 0 B
1036-
│ KV gRPC calls: 0
1037-
│ execution time: 0µs
1038-
│ estimated max memory allocated: 0 B
1039-
│ table: t137352@t137352_pkey
1040-
│ equality: ($1) = (k)
1041-
│ equality cols are key
1042-
│ locking strength: for update
1043-
1044-
└── • values
1045-
sql nodes: <hidden>
1046-
regions: <hidden>
1047-
actual row count: 1
1048-
execution time: 0µs
1049-
size: 1 column, 1 row
1028+
└── • scan
1029+
sql nodes: <hidden>
1030+
kv nodes: <hidden>
1031+
regions: <hidden>
1032+
actual row count: 0
1033+
KV time: 0µs
1034+
KV rows decoded: 0
1035+
KV bytes read: 0 B
1036+
KV gRPC calls: 0
1037+
estimated max memory allocated: 0 B
1038+
missing stats
1039+
table: t137352@t137352_pkey
1040+
spans: [/1 - /1]
1041+
locking strength: for update
10501042

10511043
statement ok
10521044
INSERT INTO t137352 VALUES (1, 2, 3);
@@ -1297,29 +1289,20 @@ quality of service: regular
12971289
│ equality: (k) = (a)
12981290
│ pred: a = 1
12991291
1300-
└── • lookup join
1301-
│ sql nodes: <hidden>
1302-
│ kv nodes: <hidden>
1303-
│ regions: <hidden>
1304-
│ actual row count: 1
1305-
│ KV time: 0µs
1306-
│ KV rows decoded: 1
1307-
│ KV pairs read: 2
1308-
│ KV bytes read: 8 B
1309-
│ KV gRPC calls: 1
1310-
│ execution time: 0µs
1311-
│ estimated max memory allocated: 0 B
1312-
│ estimated row count: 1
1313-
│ table: t137352@t137352_pkey
1314-
│ equality: ($1) = (k)
1315-
│ equality cols are key
1316-
1317-
└── • values
1318-
sql nodes: <hidden>
1319-
regions: <hidden>
1320-
actual row count: 1
1321-
execution time: 0µs
1322-
size: 1 column, 1 row
1292+
└── • scan
1293+
sql nodes: <hidden>
1294+
kv nodes: <hidden>
1295+
regions: <hidden>
1296+
actual row count: 1
1297+
KV time: 0µs
1298+
KV rows decoded: 1
1299+
KV pairs read: 2
1300+
KV bytes read: 8 B
1301+
KV gRPC calls: 1
1302+
estimated max memory allocated: 0 B
1303+
estimated row count: 1
1304+
table: t137352@t137352_pkey
1305+
spans: [/1 - /1]
13231306

13241307
statement ok
13251308
DELETE FROM t137352 WHERE true;

pkg/sql/opt/exec/execbuilder/testdata/virtual

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,4 +539,3 @@ vectorized: true
539539

540540
statement ok
541541
RESET disallow_full_table_scans;
542-

pkg/sql/opt/memo/logical_props_builder.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ func (b *logicalPropsBuilder) buildScanProps(scan *ScanExpr, rel *props.Relation
203203
}
204204
}
205205

206+
// buildPlaceholderScanProps is unimplemented. Placeholder expressions are only created
207+
// in two places:
208+
//
209+
// 1. The placeholder fast-path which entirely skips optimization.
210+
// 2. The ConvertParameterizedLookupJoinToPlaceholderScan exploration rule
211+
// which always adds the placeholder scan to an existing memo group, for
212+
// which logical properties have already been built.
213+
//
214+
// In both cases this function is never called.
206215
func (b *logicalPropsBuilder) buildPlaceholderScanProps(
207216
scan *PlaceholderScanExpr, rel *props.Relational,
208217
) {

pkg/sql/opt/norm/factory_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ func TestCopyAndReplace(t *testing.T) {
8787

8888
if e, err := o.Optimize(); err != nil {
8989
t.Fatal(err)
90-
} else if e.Op() != opt.ProjectOp || e.Child(0).Op() != opt.LookupJoinOp {
91-
t.Errorf("expected optimizer to choose a (project (lookup-join)), not (%v (%v))",
92-
e.Op(), e.Child(0).Op())
90+
} else if e.Op() != opt.PlaceholderScanOp {
91+
t.Errorf("expected optimizer to choose a placeholder scan, not %v", e.Op())
9392
}
9493

9594
m := o.Factory().DetachMemo()

0 commit comments

Comments
 (0)