github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/index_skip_table_reader_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package rowexec 12 13 import ( 14 "context" 15 "fmt" 16 "sort" 17 "testing" 18 19 "github.com/cockroachdb/cockroach/pkg/base" 20 "github.com/cockroachdb/cockroach/pkg/keys" 21 "github.com/cockroachdb/cockroach/pkg/kv" 22 "github.com/cockroachdb/cockroach/pkg/roachpb" 23 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 24 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 25 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 26 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 27 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 28 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 29 "github.com/cockroachdb/cockroach/pkg/util/encoding" 30 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 31 "github.com/cockroachdb/cockroach/pkg/util/log" 32 ) 33 34 func TestIndexSkipTableReader(t *testing.T) { 35 defer leaktest.AfterTest(t)() 36 ctx := context.Background() 37 38 s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) 39 defer s.Stopper().Stop(ctx) 40 41 // create a table t1 where each row is: 42 // 43 // | x | y | 44 // |-----------------------| 45 // | rowId/10 | rowId%10 | 46 47 xFnt1 := func(row int) tree.Datum { 48 return tree.NewDInt(tree.DInt(row / 10)) 49 } 50 yFnt1 := func(row int) tree.Datum { 51 return tree.NewDInt(tree.DInt(row % 10)) 52 } 53 54 sqlutils.CreateTable(t, sqlDB, "t1", 55 "x INT, y INT, PRIMARY KEY (x, y)", 56 99, 57 sqlutils.ToRowFn(xFnt1, yFnt1), 58 ) 59 60 // create a table t2 where each row is: 61 // 62 // | x | y | z | 63 // |---------------------------------------| 64 // | rowId / 3 | rowId / 3 + 1 | rowId | 65 66 xFnt2 := func(row int) tree.Datum { 67 return tree.NewDInt(tree.DInt(row / 3)) 68 } 69 yFnt2 := func(row int) tree.Datum { 70 return tree.NewDInt(tree.DInt(row/3 + 1)) 71 } 72 zFnt2 := func(row int) tree.Datum { 73 return tree.NewDInt(tree.DInt(row)) 74 } 75 sqlutils.CreateTable(t, sqlDB, "t2", 76 "x INT, y INT, z INT, PRIMARY KEY (x, y, z)", 77 9, 78 sqlutils.ToRowFn(xFnt2, yFnt2, zFnt2), 79 ) 80 81 // create a table t3 where each row is: 82 // 83 // | x | y | z | 84 // |-------------------------------------------------------------------| 85 // | rowId / 3 | rowId % 3 | if rowId % 2 == 0 then NULL else rowID | 86 87 xFnt3 := func(row int) tree.Datum { 88 return tree.NewDInt(tree.DInt(row / 3)) 89 } 90 yFnt3 := func(row int) tree.Datum { 91 return tree.NewDInt(tree.DInt(row % 3)) 92 } 93 zFnt3 := func(row int) tree.Datum { 94 if row%2 == 0 { 95 return tree.DNull 96 } 97 return tree.NewDInt(tree.DInt(row)) 98 } 99 sqlutils.CreateTable(t, sqlDB, "t3", 100 "x INT, y INT, z INT, PRIMARY KEY (x, y)", 101 9, 102 sqlutils.ToRowFn(xFnt3, yFnt3, zFnt3), 103 ) 104 105 // create a table t4 where each row is: 106 // 107 // | x | y | 108 // |---------------------------| 109 // | rowId/10 | rowId%10 + 1 | 110 111 xFnt4 := func(row int) tree.Datum { 112 return tree.NewDInt(tree.DInt(row / 10)) 113 } 114 yFnt4 := func(row int) tree.Datum { 115 return tree.NewDInt(tree.DInt(row%10 + 1)) 116 } 117 118 sqlutils.CreateTable(t, sqlDB, "t4", 119 "x INT, y INT, PRIMARY KEY (x, y)", 120 99, 121 sqlutils.ToRowFn(xFnt4, yFnt4), 122 ) 123 // create a secondary index on (y, x) on t4 124 runner := sqlutils.MakeSQLRunner(sqlDB) 125 runner.Exec(t, "CREATE INDEX t4_test_index ON test.t4 (y, x)") 126 127 // create some interleaved tables 128 sqlutils.CreateTable(t, sqlDB, "t5", 129 "x INT PRIMARY KEY", 130 10, 131 sqlutils.ToRowFn(yFnt1)) 132 133 xFnt6 := func(row int) tree.Datum { 134 return tree.NewDInt(tree.DInt(row/10) + 1) 135 } 136 yFnt6 := func(row int) tree.Datum { 137 return tree.NewDInt(tree.DInt(row%10) + 1) 138 } 139 // interleave a table now 140 sqlutils.CreateTableInterleaved(t, sqlDB, "t6", 141 "x INT, y INT, PRIMARY KEY(x, y)", 142 "t5 (x)", 143 99, 144 sqlutils.ToRowFn(xFnt6, yFnt6)) 145 146 // create a table t7 where each row is: 147 // 148 // | x | y | z | 149 // |-------------------------| 150 // | rowId%10 | NULL | NULL| 151 xFnt7 := func(row int) tree.Datum { 152 return tree.NewDInt(tree.DInt(row % 10)) 153 } 154 nullt7 := func(_ int) tree.Datum { 155 return tree.DNull 156 } 157 sqlutils.CreateTable(t, sqlDB, "t7", 158 "x INT, y INT, z INT, PRIMARY KEY (x), INDEX i1 (x, y DESC, z DESC), INDEX i2 (y DESC, z DESC)", 159 10, 160 sqlutils.ToRowFn(xFnt7, nullt7, nullt7)) 161 162 td1 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t1") 163 td2 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t2") 164 td3 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t3") 165 td4 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t4") 166 td5 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t5") 167 td6 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t6") 168 td7 := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t7") 169 170 makeIndexSpan := func(td *sqlbase.TableDescriptor, start, end int) execinfrapb.TableReaderSpan { 171 var span roachpb.Span 172 prefix := roachpb.Key(sqlbase.MakeIndexKeyPrefix(keys.SystemSQLCodec, td, td.PrimaryIndex.ID)) 173 span.Key = append(prefix, encoding.EncodeVarintAscending(nil, int64(start))...) 174 span.EndKey = append(span.EndKey, prefix...) 175 span.EndKey = append(span.EndKey, encoding.EncodeVarintAscending(nil, int64(end))...) 176 return execinfrapb.TableReaderSpan{Span: span} 177 } 178 179 testCases := []struct { 180 desc string 181 tableDesc *sqlbase.TableDescriptor 182 spec execinfrapb.IndexSkipTableReaderSpec 183 post execinfrapb.PostProcessSpec 184 expected string 185 }{ 186 { 187 // Distinct scan simple. 188 desc: "SimpleForward", 189 tableDesc: td1, 190 spec: execinfrapb.IndexSkipTableReaderSpec{ 191 Spans: []execinfrapb.TableReaderSpan{{Span: td1.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 192 }, 193 post: execinfrapb.PostProcessSpec{ 194 Projection: true, 195 OutputColumns: []uint32{0}, 196 }, 197 expected: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]", 198 }, 199 { 200 // Distinct scan on interleaved table parent. 201 desc: "InterleavedParent", 202 tableDesc: td5, 203 spec: execinfrapb.IndexSkipTableReaderSpec{ 204 Spans: []execinfrapb.TableReaderSpan{{Span: td5.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 205 }, 206 post: execinfrapb.PostProcessSpec{ 207 Projection: true, 208 OutputColumns: []uint32{0}, 209 }, 210 expected: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]", 211 }, 212 { 213 // Distinct scan on interleaved table child. 214 desc: "InterleavedChild", 215 tableDesc: td6, 216 spec: execinfrapb.IndexSkipTableReaderSpec{ 217 Spans: []execinfrapb.TableReaderSpan{{Span: td6.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 218 }, 219 post: execinfrapb.PostProcessSpec{ 220 Projection: true, 221 OutputColumns: []uint32{0}, 222 }, 223 expected: "[[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]]", 224 }, 225 { 226 // Distinct scan with multiple spans. 227 desc: "MultipleSpans", 228 tableDesc: td1, 229 spec: execinfrapb.IndexSkipTableReaderSpec{ 230 Spans: []execinfrapb.TableReaderSpan{makeIndexSpan(td1, 0, 3), makeIndexSpan(td1, 5, 8)}, 231 }, 232 post: execinfrapb.PostProcessSpec{ 233 Projection: true, 234 OutputColumns: []uint32{0}, 235 }, 236 expected: "[[0] [1] [2] [5] [6] [7]]", 237 }, 238 { 239 // Distinct scan with multiple spans and filter, 240 desc: "MultipleSpansWithFilter", 241 tableDesc: td1, 242 spec: execinfrapb.IndexSkipTableReaderSpec{ 243 Spans: []execinfrapb.TableReaderSpan{makeIndexSpan(td1, 0, 3), makeIndexSpan(td1, 5, 8)}, 244 }, 245 post: execinfrapb.PostProcessSpec{ 246 Filter: execinfrapb.Expression{Expr: "@1 > 3 AND @1 < 7"}, 247 Projection: true, 248 OutputColumns: []uint32{0}, 249 }, 250 expected: "[[5] [6]]", 251 }, 252 { 253 // Distinct scan with filter. 254 desc: "Filter", 255 tableDesc: td1, 256 spec: execinfrapb.IndexSkipTableReaderSpec{ 257 Spans: []execinfrapb.TableReaderSpan{{Span: td1.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 258 }, 259 post: execinfrapb.PostProcessSpec{ 260 Filter: execinfrapb.Expression{Expr: "@1 > 3 AND @1 < 7"}, 261 Projection: true, 262 OutputColumns: []uint32{0}, 263 }, 264 expected: "[[4] [5] [6]]", 265 }, 266 { 267 // Distinct scan with multiple requested columns. 268 desc: "MultipleOutputCols", 269 tableDesc: td2, 270 spec: execinfrapb.IndexSkipTableReaderSpec{ 271 Spans: []execinfrapb.TableReaderSpan{{Span: td2.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 272 }, 273 post: execinfrapb.PostProcessSpec{ 274 Projection: true, 275 OutputColumns: []uint32{0, 1}, 276 }, 277 expected: "[[0 1] [1 2] [2 3] [3 4]]", 278 }, 279 { 280 // Distinct scan on table with NULLs. 281 desc: "Nulls", 282 tableDesc: td3, 283 spec: execinfrapb.IndexSkipTableReaderSpec{ 284 Spans: []execinfrapb.TableReaderSpan{{Span: td3.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 285 }, 286 post: execinfrapb.PostProcessSpec{ 287 Projection: true, 288 OutputColumns: []uint32{0}, 289 }, 290 expected: "[[0] [1] [2] [3]]", 291 }, 292 { 293 // Distinct scan on secondary index", 294 desc: "SecondaryIdx", 295 tableDesc: td4, 296 spec: execinfrapb.IndexSkipTableReaderSpec{ 297 Spans: []execinfrapb.TableReaderSpan{{Span: td4.IndexSpan(keys.SystemSQLCodec, 2)}}, 298 IndexIdx: 1, 299 }, 300 post: execinfrapb.PostProcessSpec{ 301 Projection: true, 302 OutputColumns: []uint32{1}, 303 }, 304 expected: "[[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]]", 305 }, 306 { 307 // Distinct reverse scan simple. 308 desc: "SimpleReverse", 309 tableDesc: td1, 310 spec: execinfrapb.IndexSkipTableReaderSpec{ 311 Spans: []execinfrapb.TableReaderSpan{{Span: td1.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 312 Reverse: true, 313 }, 314 post: execinfrapb.PostProcessSpec{ 315 Projection: true, 316 OutputColumns: []uint32{0}, 317 }, 318 expected: "[[9] [8] [7] [6] [5] [4] [3] [2] [1] [0]]", 319 }, 320 { 321 // Distinct reverse scan with multiple spans. 322 desc: "MultipleSpansReverse", 323 tableDesc: td1, 324 spec: execinfrapb.IndexSkipTableReaderSpec{ 325 Spans: []execinfrapb.TableReaderSpan{makeIndexSpan(td1, 0, 3), makeIndexSpan(td1, 5, 8)}, 326 Reverse: true, 327 }, 328 post: execinfrapb.PostProcessSpec{ 329 Projection: true, 330 OutputColumns: []uint32{0}, 331 }, 332 expected: "[[7] [6] [5] [2] [1] [0]]", 333 }, 334 { 335 // Distinct reverse scan with multiple spans and filter. 336 desc: "MultipleSpansWithFilterReverse", 337 tableDesc: td1, 338 spec: execinfrapb.IndexSkipTableReaderSpec{ 339 Spans: []execinfrapb.TableReaderSpan{makeIndexSpan(td1, 0, 3), makeIndexSpan(td1, 5, 8)}, 340 Reverse: true, 341 }, 342 post: execinfrapb.PostProcessSpec{ 343 Filter: execinfrapb.Expression{Expr: "@1 > 3 AND @1 < 7"}, 344 Projection: true, 345 OutputColumns: []uint32{0}, 346 }, 347 expected: "[[6] [5]]", 348 }, 349 { 350 // Distinct reverse scan on interleaved parent. 351 desc: "InterleavedParentReverse", 352 tableDesc: td5, 353 spec: execinfrapb.IndexSkipTableReaderSpec{ 354 Spans: []execinfrapb.TableReaderSpan{{Span: td5.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 355 Reverse: true, 356 }, 357 post: execinfrapb.PostProcessSpec{ 358 Projection: true, 359 OutputColumns: []uint32{0}, 360 }, 361 expected: "[[9] [8] [7] [6] [5] [4] [3] [2] [1] [0]]", 362 }, 363 { 364 // Distinct reverse scan with multiple spans on interleaved parent. 365 desc: "InterleavedParentMultipleSpansReverse", 366 tableDesc: td5, 367 spec: execinfrapb.IndexSkipTableReaderSpec{ 368 Spans: []execinfrapb.TableReaderSpan{makeIndexSpan(td5, 0, 3), makeIndexSpan(td5, 5, 8)}, 369 Reverse: true, 370 }, 371 post: execinfrapb.PostProcessSpec{ 372 Projection: true, 373 OutputColumns: []uint32{0}, 374 }, 375 expected: "[[7] [6] [5] [2] [1] [0]]", 376 }, 377 { 378 // Distinct reverse scan on interleaved child. 379 desc: "InterleavedChildReverse", 380 tableDesc: td6, 381 spec: execinfrapb.IndexSkipTableReaderSpec{ 382 Spans: []execinfrapb.TableReaderSpan{{Span: td6.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 383 Reverse: true, 384 }, 385 post: execinfrapb.PostProcessSpec{ 386 Projection: true, 387 OutputColumns: []uint32{0}, 388 }, 389 expected: "[[10] [9] [8] [7] [6] [5] [4] [3] [2] [1]]", 390 }, 391 { 392 // Distinct scan on index with multiple null values 393 desc: "IndexMultipleNulls", 394 tableDesc: td7, 395 spec: execinfrapb.IndexSkipTableReaderSpec{ 396 Spans: []execinfrapb.TableReaderSpan{{Span: td7.IndexSpan(keys.SystemSQLCodec, 2)}}, 397 IndexIdx: 1, 398 }, 399 post: execinfrapb.PostProcessSpec{ 400 Projection: true, 401 OutputColumns: []uint32{0}, 402 }, 403 expected: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]", 404 }, 405 { 406 // Distinct scan on index with only null values 407 desc: "IndexAllNulls", 408 tableDesc: td7, 409 spec: execinfrapb.IndexSkipTableReaderSpec{ 410 Spans: []execinfrapb.TableReaderSpan{{Span: td7.IndexSpan(keys.SystemSQLCodec, 3)}}, 411 IndexIdx: 2, 412 }, 413 post: execinfrapb.PostProcessSpec{ 414 Projection: true, 415 OutputColumns: []uint32{1}, 416 }, 417 expected: "[[NULL]]", 418 }, 419 } 420 421 for _, c := range testCases { 422 t.Run(c.desc, func(t *testing.T) { 423 ts := c.spec 424 ts.Table = *c.tableDesc 425 426 evalCtx := tree.MakeTestingEvalContext(s.ClusterSettings()) 427 defer evalCtx.Stop(ctx) 428 flowCtx := execinfra.FlowCtx{ 429 EvalCtx: &evalCtx, 430 Cfg: &execinfra.ServerConfig{Settings: s.ClusterSettings()}, 431 Txn: kv.NewTxn(ctx, s.DB(), s.NodeID()), 432 NodeID: evalCtx.NodeID, 433 } 434 435 tr, err := newIndexSkipTableReader(&flowCtx, 0 /* processorID */, &ts, &c.post, nil) 436 437 if err != nil { 438 t.Fatal(err) 439 } 440 441 var results execinfra.RowSource 442 tr.Start(ctx) 443 results = tr 444 445 var res sqlbase.EncDatumRows 446 for { 447 row, meta := results.Next() 448 if meta != nil && meta.LeafTxnFinalState == nil { 449 t.Fatalf("unexpected metadata: %+v", meta) 450 } 451 if row == nil { 452 break 453 } 454 res = append(res, row.Copy()) 455 } 456 if result := res.String(tr.OutputTypes()); result != c.expected { 457 t.Errorf("invalid results: %s, expected %s'", result, c.expected) 458 } 459 460 }) 461 } 462 463 } 464 465 func TestIndexSkipTableReaderMisplannedRangesMetadata(t *testing.T) { 466 defer leaktest.AfterTest(t)() 467 ctx := context.Background() 468 tc := serverutils.StartTestCluster(t, 3, 469 base.TestClusterArgs{ 470 ReplicationMode: base.ReplicationManual, 471 ServerArgs: base.TestServerArgs{ 472 UseDatabase: "test", 473 }, 474 }) 475 defer tc.Stopper().Stop(ctx) 476 477 db := tc.ServerConn(0) 478 sqlutils.CreateTable(t, db, "t", 479 "num INT PRIMARY KEY", 480 3, 481 sqlutils.ToRowFn(sqlutils.RowIdxFn), 482 ) 483 484 _, err := db.Exec(` 485 ALTER TABLE t SPLIT AT VALUES (1), (2), (3); 486 ALTER TABLE t EXPERIMENTAL_RELOCATE VALUES (ARRAY[2], 1), (ARRAY[1], 2), (ARRAY[3], 3); 487 `) 488 if err != nil { 489 t.Fatal(err) 490 } 491 492 kvDB := tc.Server(0).DB() 493 td := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t") 494 495 st := tc.Server(0).ClusterSettings() 496 evalCtx := tree.MakeTestingEvalContext(st) 497 defer evalCtx.Stop(ctx) 498 nodeID := tc.Server(0).NodeID() 499 flowCtx := execinfra.FlowCtx{ 500 EvalCtx: &evalCtx, 501 Cfg: &execinfra.ServerConfig{Settings: st}, 502 Txn: kv.NewTxn(ctx, tc.Server(0).DB(), nodeID), 503 NodeID: evalCtx.NodeID, 504 } 505 spec := execinfrapb.IndexSkipTableReaderSpec{ 506 Spans: []execinfrapb.TableReaderSpan{{Span: td.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 507 Table: *td, 508 } 509 post := execinfrapb.PostProcessSpec{ 510 Projection: true, 511 OutputColumns: []uint32{0}, 512 } 513 514 t.Run("", func(t *testing.T) { 515 tr, err := newIndexSkipTableReader(&flowCtx, 0, &spec, &post, nil) 516 if err != nil { 517 t.Fatal(err) 518 } 519 tr.Start(ctx) 520 var res sqlbase.EncDatumRows 521 var metas []*execinfrapb.ProducerMetadata 522 for { 523 row, meta := tr.Next() 524 if meta != nil { 525 metas = append(metas, meta) 526 continue 527 } 528 if row == nil { 529 break 530 } 531 res = append(res, row) 532 } 533 if len(res) != 3 { 534 t.Fatalf("expected 3 rows, got: %d", len(res)) 535 } 536 var misplannedRanges []roachpb.RangeInfo 537 for _, m := range metas { 538 if len(m.Ranges) > 0 { 539 misplannedRanges = m.Ranges 540 } else if m.LeafTxnFinalState == nil { 541 t.Fatalf("expected only txn coord meta or misplanned ranges, got: %+v", metas) 542 } 543 } 544 545 if len(misplannedRanges) != 2 { 546 t.Fatalf("expected 2 misplanned ranges, got: %+v", misplannedRanges) 547 } 548 549 // The metadata about misplanned ranges can come in any order (it depends on 550 // the order in which parallel sub-batches complete after having been split by 551 // DistSender). 552 sort.Slice(misplannedRanges, func(i, j int) bool { 553 return misplannedRanges[i].Lease.Replica.NodeID < misplannedRanges[j].Lease.Replica.NodeID 554 }) 555 if misplannedRanges[0].Lease.Replica.NodeID != 2 || 556 misplannedRanges[1].Lease.Replica.NodeID != 3 { 557 t.Fatalf("expected misplanned ranges from nodes 2 and 3, got: %+v", metas[0]) 558 } 559 }) 560 } 561 562 func BenchmarkIndexScanTableReader(b *testing.B) { 563 defer leaktest.AfterTest(b)() 564 565 logScope := log.Scope(b) 566 defer logScope.Close(b) 567 568 ctx := context.Background() 569 570 s, sqlDB, kvDB := serverutils.StartServer(b, base.TestServerArgs{}) 571 defer s.Stopper().Stop(ctx) 572 573 evalCtx := tree.MakeTestingEvalContext(s.ClusterSettings()) 574 defer evalCtx.Stop(ctx) 575 576 // test for number of rows in the table 577 for _, numRows := range []int{1 << 4, 1 << 8, 1 << 12, 1 << 16, 1 << 18} { 578 // test for a ratio of values from 1 unique value of the first column 579 // of the primary key to x values of the second column 580 for _, valueRatio := range []int{1, 100, 500, 1000, 5000, 10000} { 581 if valueRatio > numRows { 582 continue 583 } 584 tableName := fmt.Sprintf("t_%d_%d", numRows, valueRatio) 585 xFn := func(row int) tree.Datum { 586 return tree.NewDInt(tree.DInt(row / valueRatio)) 587 } 588 yFn := func(row int) tree.Datum { 589 return tree.NewDInt(tree.DInt(row % valueRatio)) 590 } 591 592 sqlutils.CreateTable( 593 b, sqlDB, tableName, 594 "x INT, y INT, PRIMARY KEY (x, y)", 595 numRows, 596 sqlutils.ToRowFn(xFn, yFn)) 597 598 expectedCount := (numRows / valueRatio) 599 if valueRatio != 1 { 600 expectedCount++ 601 } 602 603 tableDesc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", tableName) 604 605 runner := func(reader execinfra.RowSource, b *testing.B) { 606 reader.Start(ctx) 607 count := 0 608 for { 609 row, meta := reader.Next() 610 if meta != nil && meta.LeafTxnFinalState == nil && meta.Metrics == nil { 611 b.Fatalf("unexpected metadata: %+v", meta) 612 } 613 if row != nil { 614 count++ 615 } else if meta == nil { 616 break 617 } 618 } 619 if count != expectedCount { 620 b.Fatalf("found %d rows, expected %d", count, expectedCount) 621 } 622 } 623 624 flowCtxTableReader := execinfra.FlowCtx{ 625 EvalCtx: &evalCtx, 626 Cfg: &execinfra.ServerConfig{Settings: s.ClusterSettings()}, 627 Txn: kv.NewTxn(ctx, s.DB(), s.NodeID()), 628 NodeID: evalCtx.NodeID, 629 } 630 631 b.Run(fmt.Sprintf("TableReader+Distinct-rows=%d-ratio=%d", numRows, valueRatio), func(b *testing.B) { 632 spec := execinfrapb.TableReaderSpec{ 633 Table: *tableDesc, 634 Spans: []execinfrapb.TableReaderSpan{{Span: tableDesc.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 635 } 636 post := execinfrapb.PostProcessSpec{ 637 Projection: true, 638 OutputColumns: []uint32{0}, 639 } 640 641 specDistinct := execinfrapb.DistinctSpec{ 642 OrderedColumns: []uint32{0}, 643 DistinctColumns: []uint32{0}, 644 } 645 postDistinct := execinfrapb.PostProcessSpec{} 646 647 b.ResetTimer() 648 for i := 0; i < b.N; i++ { 649 tr, err := newTableReader(&flowCtxTableReader, 0, &spec, &post, nil) 650 if err != nil { 651 b.Fatal(err) 652 } 653 dist, err := newDistinct(&flowCtxTableReader, 0, &specDistinct, tr, &postDistinct, nil) 654 if err != nil { 655 b.Fatal(err) 656 } 657 runner(dist, b) 658 } 659 }) 660 661 flowCtxIndexSkipTableReader := execinfra.FlowCtx{ 662 EvalCtx: &evalCtx, 663 Cfg: &execinfra.ServerConfig{Settings: s.ClusterSettings()}, 664 Txn: kv.NewTxn(ctx, s.DB(), s.NodeID()), 665 NodeID: evalCtx.NodeID, 666 } 667 668 // run the index skip table reader 669 b.Run(fmt.Sprintf("IndexSkipTableReader-rows=%d-ratio=%d", numRows, valueRatio), func(b *testing.B) { 670 spec := execinfrapb.IndexSkipTableReaderSpec{ 671 Table: *tableDesc, 672 Spans: []execinfrapb.TableReaderSpan{{Span: tableDesc.PrimaryIndexSpan(keys.SystemSQLCodec)}}, 673 } 674 post := execinfrapb.PostProcessSpec{ 675 OutputColumns: []uint32{0}, 676 Projection: true, 677 } 678 b.ResetTimer() 679 for i := 0; i < b.N; i++ { 680 it, err := newIndexSkipTableReader(&flowCtxIndexSkipTableReader, 0, &spec, &post, nil) 681 if err != nil { 682 b.Fatal(err) 683 } 684 runner(it, b) 685 } 686 }) 687 } 688 } 689 }