github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/bench/bench_test.go (about)

     1  // Copyright 2015 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 bench
    12  
    13  import (
    14  	"bytes"
    15  	"context"
    16  	"fmt"
    17  	"math/rand"
    18  	"reflect"
    19  	"runtime"
    20  	"strconv"
    21  	"strings"
    22  	"sync/atomic"
    23  	"testing"
    24  
    25  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    26  	"github.com/cockroachdb/cockroach/pkg/util/log"
    27  	"github.com/cockroachdb/cockroach/pkg/util/randutil"
    28  	_ "github.com/go-sql-driver/mysql"
    29  	_ "github.com/lib/pq"
    30  )
    31  
    32  func runBenchmarkSelect1(b *testing.B, db *sqlutils.SQLRunner) {
    33  	b.ResetTimer()
    34  	for i := 0; i < b.N; i++ {
    35  		rows := db.Query(b, `SELECT 1`)
    36  		rows.Close()
    37  	}
    38  	b.StopTimer()
    39  }
    40  
    41  func BenchmarkSelect1(b *testing.B) {
    42  	defer log.Scope(b).Close(b)
    43  	ForEachDB(b, runBenchmarkSelect1)
    44  }
    45  
    46  func runBenchmarkSelectWithTargetsAndFilter(
    47  	b *testing.B, db *sqlutils.SQLRunner, targets, filter string, args ...interface{},
    48  ) {
    49  	defer func() {
    50  		db.Exec(b, `DROP TABLE IF EXISTS bench.select`)
    51  	}()
    52  
    53  	db.Exec(b, `CREATE TABLE bench.select (k INT PRIMARY KEY, a INT, b INT, c INT, d INT)`)
    54  
    55  	var buf bytes.Buffer
    56  	buf.WriteString(`INSERT INTO bench.select VALUES `)
    57  
    58  	// We insert all combinations of values between 1 and num for columns a, b, c. The intention is
    59  	// to benchmark the expression parsing and query setup so we don't want to have many rows to go
    60  	// through.
    61  	const num = 3
    62  	row := 0
    63  	for i := 1; i <= num; i++ {
    64  		for j := 1; j <= num; j++ {
    65  			for k := 1; k <= num; k++ {
    66  				if row > 0 {
    67  					buf.WriteString(", ")
    68  				}
    69  				row++
    70  				fmt.Fprintf(&buf, "(%d, %d, %d, %d)", row, i, j, k)
    71  			}
    72  		}
    73  	}
    74  	db.Exec(b, buf.String())
    75  
    76  	b.ResetTimer()
    77  	for i := 0; i < b.N; i++ {
    78  		rows := db.Query(b, fmt.Sprintf(`SELECT %s FROM bench.select WHERE %s`, targets, filter), args...)
    79  		rows.Close()
    80  	}
    81  	b.StopTimer()
    82  }
    83  
    84  // BenchmarkSelect2 runs a SELECT query with non-trivial expressions. The main
    85  // purpose is to detect major regressions in query expression processing.
    86  func BenchmarkSelect2(b *testing.B) {
    87  	defer log.Scope(b).Close(b)
    88  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
    89  		targets := `a, b, c, a+b, a+1, (a+2)*(b+3)*(c+4)`
    90  		filter := `(a = 1) OR ((a = 2) and (b = c)) OR (a + b = 3) OR (2*a + 4*b = 4*c)`
    91  		runBenchmarkSelectWithTargetsAndFilter(b, db, targets, filter)
    92  	})
    93  }
    94  
    95  // BenchmarkSelect3 runs a SELECT query with non-trivial expressions. The main
    96  // purpose is to quantify regressions in numeric type processing.
    97  func BenchmarkSelect3(b *testing.B) {
    98  	defer log.Scope(b).Close(b)
    99  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   100  		targets := `a/b, b/c, c != 3.3 + $1, a = 2.0, c * 9.0`
   101  		filter := `a > 1 AND b < 4.5`
   102  		args := []interface{}{1.0}
   103  		runBenchmarkSelectWithTargetsAndFilter(b, db, targets, filter, args...)
   104  	})
   105  }
   106  
   107  func BenchmarkCount(b *testing.B) {
   108  	if testing.Short() {
   109  		b.Skip("short flag")
   110  	}
   111  	defer log.Scope(b).Close(b)
   112  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   113  		defer func() {
   114  			db.Exec(b, `DROP TABLE IF EXISTS bench.count`)
   115  		}()
   116  
   117  		db.Exec(b, `CREATE TABLE bench.count (k INT PRIMARY KEY, v TEXT)`)
   118  
   119  		var buf bytes.Buffer
   120  		val := 0
   121  		for i := 0; i < 100; i++ {
   122  			buf.Reset()
   123  			buf.WriteString(`INSERT INTO bench.count VALUES `)
   124  			for j := 0; j < 1000; j++ {
   125  				if j > 0 {
   126  					buf.WriteString(", ")
   127  				}
   128  				fmt.Fprintf(&buf, "(%d, '%s')", val, strconv.Itoa(val))
   129  				val++
   130  			}
   131  			db.Exec(b, buf.String())
   132  		}
   133  
   134  		b.ResetTimer()
   135  
   136  		for i := 0; i < b.N; i++ {
   137  			db.Exec(b, "SELECT count(*) FROM bench.count")
   138  		}
   139  		b.StopTimer()
   140  	})
   141  }
   142  
   143  func BenchmarkCountTwoCF(b *testing.B) {
   144  	if testing.Short() {
   145  		b.Skip("short flag")
   146  	}
   147  	defer log.Scope(b).Close(b)
   148  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   149  		defer func() {
   150  			db.Exec(b, `DROP TABLE IF EXISTS bench.count`)
   151  		}()
   152  
   153  		db.Exec(b, `CREATE TABLE bench.count (k INT PRIMARY KEY, v TEXT, FAMILY (k), FAMILY (v))`)
   154  
   155  		var buf bytes.Buffer
   156  		val := 0
   157  		for i := 0; i < 100; i++ {
   158  			buf.Reset()
   159  			buf.WriteString(`INSERT INTO bench.count VALUES `)
   160  			for j := 0; j < 1000; j++ {
   161  				if j > 0 {
   162  					buf.WriteString(", ")
   163  				}
   164  				fmt.Fprintf(&buf, "(%d, '%s')", val, strconv.Itoa(val))
   165  				val++
   166  			}
   167  			db.Exec(b, buf.String())
   168  		}
   169  
   170  		b.ResetTimer()
   171  
   172  		for i := 0; i < b.N; i++ {
   173  			db.Exec(b, "SELECT count(*) FROM bench.count")
   174  		}
   175  		b.StopTimer()
   176  	})
   177  }
   178  
   179  func BenchmarkSort(b *testing.B) {
   180  	if testing.Short() {
   181  		b.Skip("short flag")
   182  	}
   183  	defer log.Scope(b).Close(b)
   184  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   185  		defer func() {
   186  			db.Exec(b, `DROP TABLE IF EXISTS bench.sort`)
   187  		}()
   188  
   189  		db.Exec(b, `CREATE TABLE bench.sort (k INT PRIMARY KEY, v INT)`)
   190  
   191  		var buf bytes.Buffer
   192  		val := 0
   193  		for i := 0; i < 100; i++ {
   194  			buf.Reset()
   195  			buf.WriteString(`INSERT INTO bench.sort VALUES `)
   196  			for j := 0; j < 1000; j++ {
   197  				if j > 0 {
   198  					buf.WriteString(", ")
   199  				}
   200  				fmt.Fprintf(&buf, "(%d, %d)", val, -val)
   201  				val++
   202  			}
   203  			db.Exec(b, buf.String())
   204  		}
   205  
   206  		b.ResetTimer()
   207  
   208  		for i := 0; i < b.N; i++ {
   209  			db.Exec(b, "SELECT * FROM bench.sort ORDER BY v")
   210  		}
   211  		b.StopTimer()
   212  	})
   213  }
   214  
   215  // BenchmarkTableResolution benchmarks table name resolution
   216  // for a variety of different naming schemes.
   217  func BenchmarkTableResolution(b *testing.B) {
   218  	if testing.Short() {
   219  		b.Skip("short flag")
   220  	}
   221  	defer log.Scope(b).Close(b)
   222  
   223  	for _, createTempTables := range []bool{false, true} {
   224  		b.Run(fmt.Sprintf("temp_schema_exists:%t", createTempTables), func(b *testing.B) {
   225  			benchmarkCockroach(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   226  				defer func() {
   227  					db.Exec(b, `DROP TABLE IF EXISTS bench.tbl`)
   228  					if createTempTables {
   229  						db.Exec(b, `DROP TABLE IF EXISTS bench.pg_temp.temp_tbl`)
   230  					}
   231  				}()
   232  
   233  				db.Exec(b, `
   234  			USE bench;
   235  			CREATE TABLE tbl (k INT PRIMARY KEY, v INT);
   236  		`)
   237  
   238  				type benchCase struct {
   239  					desc    string
   240  					tblName string
   241  				}
   242  				cases := []benchCase{
   243  					{"table", "tbl"},
   244  					{"database.table", "bench.tbl"},
   245  					{"database.public.table", "bench.public.tbl"},
   246  					{"public.table", "public.tbl"},
   247  				}
   248  				if createTempTables {
   249  					db.Exec(b, `
   250  						SET experimental_enable_temp_tables=true;
   251  						CREATE TEMP TABLE temp_tbl (k INT PRIMARY KEY);
   252  					`)
   253  					cases = append(cases, []benchCase{
   254  						{"temp_table", "temp_tbl"},
   255  						{"database.pg_temp.table", "bench.pg_temp.temp_tbl"},
   256  						{"pg_temp.table", "pg_temp.temp_tbl"},
   257  					}...)
   258  				}
   259  				for _, c := range cases {
   260  					b.Run(c.desc, func(b *testing.B) {
   261  						query := "SELECT * FROM " + c.tblName
   262  						b.ResetTimer()
   263  						for i := 0; i < b.N; i++ {
   264  							db.Exec(b, query)
   265  						}
   266  						b.StopTimer()
   267  					})
   268  				}
   269  			})
   270  		})
   271  	}
   272  }
   273  
   274  // runBenchmarkInsert benchmarks inserting count rows into a table.
   275  func runBenchmarkInsert(b *testing.B, db *sqlutils.SQLRunner, count int) {
   276  	defer func() {
   277  		db.Exec(b, `DROP TABLE IF EXISTS bench.insert`)
   278  	}()
   279  
   280  	db.Exec(b, `CREATE TABLE bench.insert (k INT PRIMARY KEY)`)
   281  
   282  	b.ResetTimer()
   283  	var buf bytes.Buffer
   284  	val := 0
   285  	for i := 0; i < b.N; i++ {
   286  		buf.Reset()
   287  		buf.WriteString(`INSERT INTO bench.insert VALUES `)
   288  		for j := 0; j < count; j++ {
   289  			if j > 0 {
   290  				buf.WriteString(", ")
   291  			}
   292  			fmt.Fprintf(&buf, "(%d)", val)
   293  			val++
   294  		}
   295  		db.Exec(b, buf.String())
   296  	}
   297  	b.StopTimer()
   298  
   299  }
   300  
   301  // runBenchmarkInsertFK benchmarks inserting count rows into a table with a
   302  // present foreign key into another table.
   303  func runBenchmarkInsertFK(b *testing.B, db *sqlutils.SQLRunner, count int) {
   304  	for _, nFks := range []int{1, 5, 10} {
   305  		b.Run(fmt.Sprintf("nFks=%d", nFks), func(b *testing.B) {
   306  			defer func() {
   307  				dropStmt := "DROP TABLE IF EXISTS bench.insert"
   308  				for i := 0; i < nFks; i++ {
   309  					dropStmt += fmt.Sprintf(",bench.fk%d", i)
   310  				}
   311  				db.Exec(b, dropStmt)
   312  			}()
   313  
   314  			for i := 0; i < nFks; i++ {
   315  				db.Exec(b, fmt.Sprintf(`CREATE TABLE bench.fk%d (k INT PRIMARY KEY)`, i))
   316  				db.Exec(b, fmt.Sprintf(`INSERT INTO bench.fk%d VALUES(1), (2), (3)`, i))
   317  			}
   318  
   319  			createStmt := `CREATE TABLE bench.insert (k INT PRIMARY KEY`
   320  			valuesStr := "(%d"
   321  			for i := 0; i < nFks; i++ {
   322  				createStmt += fmt.Sprintf(",fk%d INT, FOREIGN KEY(fk%d) REFERENCES bench.fk%d(k)", i, i, i)
   323  				valuesStr += ",1"
   324  			}
   325  			createStmt += ")"
   326  			valuesStr += ")"
   327  			db.Exec(b, createStmt)
   328  
   329  			b.ResetTimer()
   330  			var buf bytes.Buffer
   331  			val := 0
   332  			for i := 0; i < b.N; i++ {
   333  				buf.Reset()
   334  				buf.WriteString(`INSERT INTO bench.insert VALUES `)
   335  				for j := 0; j < count; j++ {
   336  					if j > 0 {
   337  						buf.WriteString(", ")
   338  					}
   339  					fmt.Fprintf(&buf, valuesStr, val)
   340  					val++
   341  				}
   342  				db.Exec(b, buf.String())
   343  			}
   344  			b.StopTimer()
   345  
   346  		})
   347  	}
   348  }
   349  
   350  // runBenchmarkInsertSecondaryIndex benchmarks inserting count rows into a table with a
   351  // secondary index.
   352  func runBenchmarkInsertSecondaryIndex(b *testing.B, db *sqlutils.SQLRunner, count int) {
   353  	defer func() {
   354  		db.Exec(b, `DROP TABLE IF EXISTS bench.insert`)
   355  	}()
   356  
   357  	db.Exec(b, `CREATE TABLE bench.insert (k INT PRIMARY KEY, v INT,  INDEX(v))`)
   358  
   359  	for i := 0; i < 10; i++ {
   360  		db.Exec(b, `CREATE INDEX ON bench.insert (v)`)
   361  	}
   362  
   363  	b.ResetTimer()
   364  	var buf bytes.Buffer
   365  	val := 0
   366  	for i := 0; i < b.N; i++ {
   367  		buf.Reset()
   368  		buf.WriteString(`INSERT INTO bench.insert VALUES `)
   369  		for j := 0; j < count; j++ {
   370  			if j > 0 {
   371  				buf.WriteString(", ")
   372  			}
   373  			fmt.Fprintf(&buf, "(%d, %d)", val, val)
   374  			val++
   375  		}
   376  		db.Exec(b, buf.String())
   377  	}
   378  	b.StopTimer()
   379  }
   380  
   381  func BenchmarkSQL(b *testing.B) {
   382  	if testing.Short() {
   383  		b.Skip("short flag")
   384  	}
   385  	defer log.Scope(b).Close(b)
   386  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   387  		for _, runFn := range []func(*testing.B, *sqlutils.SQLRunner, int){
   388  			runBenchmarkDelete,
   389  			runBenchmarkInsert,
   390  			runBenchmarkInsertDistinct,
   391  			runBenchmarkInsertFK,
   392  			runBenchmarkInsertSecondaryIndex,
   393  			runBenchmarkInterleavedSelect,
   394  			runBenchmarkInterleavedFK,
   395  			runBenchmarkTrackChoices,
   396  			runBenchmarkUpdate,
   397  			runBenchmarkUpsert,
   398  		} {
   399  			fnName := runtime.FuncForPC(reflect.ValueOf(runFn).Pointer()).Name()
   400  			fnName = strings.TrimPrefix(fnName, "github.com/cockroachdb/cockroach/pkg/bench.runBenchmark")
   401  			b.Run(fnName, func(b *testing.B) {
   402  				for _, count := range []int{1, 10, 100, 1000} {
   403  					b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) {
   404  						runFn(b, db, count)
   405  					})
   406  				}
   407  			})
   408  		}
   409  	})
   410  }
   411  
   412  // runBenchmarkUpdate benchmarks updating count random rows in a table.
   413  func runBenchmarkUpdate(b *testing.B, db *sqlutils.SQLRunner, count int) {
   414  	defer func() {
   415  		db.Exec(b, `DROP TABLE IF EXISTS bench.update`)
   416  	}()
   417  
   418  	const rows = 10000
   419  	db.Exec(b, `CREATE TABLE bench.update (k INT PRIMARY KEY, v INT)`)
   420  
   421  	var buf bytes.Buffer
   422  	buf.WriteString(`INSERT INTO bench.update VALUES `)
   423  	for i := 0; i < rows; i++ {
   424  		if i > 0 {
   425  			buf.WriteString(", ")
   426  		}
   427  		fmt.Fprintf(&buf, "(%d, %d)", i, i)
   428  	}
   429  	db.Exec(b, buf.String())
   430  
   431  	s := rand.New(rand.NewSource(5432))
   432  
   433  	b.ResetTimer()
   434  	for i := 0; i < b.N; i++ {
   435  		buf.Reset()
   436  		buf.WriteString(`UPDATE bench.update SET v = v + 1 WHERE k IN (`)
   437  		for j := 0; j < count; j++ {
   438  			if j > 0 {
   439  				buf.WriteString(", ")
   440  			}
   441  			fmt.Fprintf(&buf, `%d`, s.Intn(rows))
   442  		}
   443  		buf.WriteString(`)`)
   444  		db.Exec(b, buf.String())
   445  	}
   446  	b.StopTimer()
   447  }
   448  
   449  // runBenchmarkUpsert benchmarks upserting count rows in a table.
   450  func runBenchmarkUpsert(b *testing.B, db *sqlutils.SQLRunner, count int) {
   451  	defer func() {
   452  		db.Exec(b, `DROP TABLE IF EXISTS bench.upsert`)
   453  	}()
   454  
   455  	db.Exec(b, `CREATE TABLE bench.upsert (k INT PRIMARY KEY, v INT)`)
   456  
   457  	// Upsert in Cockroach doesn't let you conflict the same row twice in one
   458  	// statement (fwiw, neither does Postgres), so build one statement that
   459  	// inserts half the values requested by `count` followed by a statement that
   460  	// updates each of the values just inserted. This also weighs the benchmark
   461  	// 50/50 for inserts vs updates.
   462  	var upsertBuf bytes.Buffer
   463  	upsertBuf.WriteString(`UPSERT INTO bench.upsert VALUES `)
   464  	for j := 0; j < count; j += 2 {
   465  		if j > 0 {
   466  			upsertBuf.WriteString(`, `)
   467  		}
   468  		fmt.Fprintf(&upsertBuf, "($1+%d, unique_rowid())", j)
   469  	}
   470  
   471  	b.ResetTimer()
   472  	key := 0
   473  	for i := 0; i < b.N; i++ {
   474  		db.Exec(b, upsertBuf.String(), key)
   475  		db.Exec(b, upsertBuf.String(), key)
   476  		key += count
   477  	}
   478  	b.StopTimer()
   479  }
   480  
   481  // runBenchmarkDelete benchmarks deleting count rows from a table.
   482  func runBenchmarkDelete(b *testing.B, db *sqlutils.SQLRunner, rows int) {
   483  	defer func() {
   484  		db.Exec(b, `DROP TABLE IF EXISTS bench.delete`)
   485  	}()
   486  
   487  	db.Exec(b, `CREATE TABLE bench.delete (k INT PRIMARY KEY, v1 INT, v2 INT, v3 INT)`)
   488  
   489  	b.ResetTimer()
   490  	var buf bytes.Buffer
   491  	for i := 0; i < b.N; i++ {
   492  		b.StopTimer()
   493  		buf.Reset()
   494  		buf.WriteString(`INSERT INTO bench.delete VALUES `)
   495  		for j := 0; j < rows; j++ {
   496  			if j > 0 {
   497  				buf.WriteString(", ")
   498  			}
   499  			fmt.Fprintf(&buf, "(%d, %d, %d, %d)", j, j, j, j)
   500  		}
   501  		db.Exec(b, buf.String())
   502  		b.StartTimer()
   503  
   504  		buf.Reset()
   505  		buf.WriteString(`DELETE FROM bench.delete WHERE k IN (`)
   506  		for j := 0; j < rows; j++ {
   507  			if j > 0 {
   508  				buf.WriteString(", ")
   509  			}
   510  			fmt.Fprintf(&buf, `%d`, j)
   511  		}
   512  		buf.WriteString(`)`)
   513  		db.Exec(b, buf.String())
   514  	}
   515  	b.StopTimer()
   516  }
   517  
   518  // runBenchmarkScan benchmarks scanning a table containing count rows.
   519  func runBenchmarkScan(b *testing.B, db *sqlutils.SQLRunner, count int, limit int) {
   520  	defer func() {
   521  		db.Exec(b, `DROP TABLE IF EXISTS bench.scan`)
   522  	}()
   523  
   524  	db.Exec(b, `CREATE TABLE bench.scan (k INT PRIMARY KEY)`)
   525  
   526  	var buf bytes.Buffer
   527  	buf.WriteString(`INSERT INTO bench.scan VALUES `)
   528  	for i := 0; i < count; i++ {
   529  		if i > 0 {
   530  			buf.WriteString(", ")
   531  		}
   532  		fmt.Fprintf(&buf, "(%d)", i)
   533  	}
   534  	db.Exec(b, buf.String())
   535  
   536  	query := `SELECT * FROM bench.scan`
   537  	if limit != 0 {
   538  		query = fmt.Sprintf(`%s LIMIT %d`, query, limit)
   539  	}
   540  
   541  	b.ResetTimer()
   542  	for i := 0; i < b.N; i++ {
   543  		rows := db.Query(b, query)
   544  		n := 0
   545  		for rows.Next() {
   546  			n++
   547  		}
   548  		rows.Close()
   549  		if err := rows.Err(); err != nil {
   550  			b.Fatal(err)
   551  		}
   552  		expected := count
   553  		if limit != 0 && limit < expected {
   554  			expected = limit
   555  		}
   556  		if n != expected {
   557  			b.Fatalf("unexpected result count: %d (expected %d)", n, expected)
   558  		}
   559  	}
   560  	b.StopTimer()
   561  }
   562  
   563  func BenchmarkScan(b *testing.B) {
   564  	if testing.Short() {
   565  		b.Skip("short flag")
   566  	}
   567  	defer log.Scope(b).Close(b)
   568  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   569  		for _, count := range []int{1, 10, 100, 1000, 10000} {
   570  			b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) {
   571  				for _, limit := range []int{0, 1, 10, 100} {
   572  					b.Run(fmt.Sprintf("limit=%d", limit), func(b *testing.B) {
   573  						runBenchmarkScan(b, db, count, limit)
   574  					})
   575  				}
   576  			})
   577  		}
   578  	})
   579  }
   580  
   581  // runBenchmarkScanFilter benchmarks scanning (w/filter) from a table containing count1 * count2 rows.
   582  func runBenchmarkScanFilter(
   583  	b *testing.B, db *sqlutils.SQLRunner, count1, count2 int, limit int, filter string,
   584  ) {
   585  	defer func() {
   586  		db.Exec(b, `DROP TABLE IF EXISTS bench.scan2`)
   587  	}()
   588  
   589  	db.Exec(b, `CREATE TABLE bench.scan2 (a INT, b INT, PRIMARY KEY (a, b))`)
   590  
   591  	var buf bytes.Buffer
   592  	buf.WriteString(`INSERT INTO bench.scan2 VALUES `)
   593  	for i := 0; i < count1; i++ {
   594  		for j := 0; j < count2; j++ {
   595  			if i+j > 0 {
   596  				buf.WriteString(", ")
   597  			}
   598  			fmt.Fprintf(&buf, "(%d, %d)", i, j)
   599  		}
   600  	}
   601  	db.Exec(b, buf.String())
   602  
   603  	query := fmt.Sprintf(`SELECT * FROM bench.scan2 WHERE %s`, filter)
   604  	if limit != 0 {
   605  		query += fmt.Sprintf(` LIMIT %d`, limit)
   606  	}
   607  
   608  	b.ResetTimer()
   609  	for i := 0; i < b.N; i++ {
   610  		rows := db.Query(b, query)
   611  		n := 0
   612  		for rows.Next() {
   613  			n++
   614  		}
   615  		rows.Close()
   616  		if err := rows.Err(); err != nil {
   617  			b.Fatal(err)
   618  		}
   619  	}
   620  	b.StopTimer()
   621  }
   622  
   623  func BenchmarkScanFilter(b *testing.B) {
   624  	defer log.Scope(b).Close(b)
   625  	const count1 = 25
   626  	const count2 = 400
   627  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   628  		b.Run(fmt.Sprintf("count1=%d", count1), func(b *testing.B) {
   629  			b.Run(fmt.Sprintf("count2=%d", count2), func(b *testing.B) {
   630  				for _, limit := range []int{1, 10, 50} {
   631  					b.Run(fmt.Sprintf("limit=%d", limit), func(b *testing.B) {
   632  						runBenchmarkScanFilter(
   633  							b, db, count1, count2, limit,
   634  							`a IN (1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 20, 21, 23) AND b < 10*a`,
   635  						)
   636  					})
   637  				}
   638  
   639  			})
   640  		})
   641  	})
   642  }
   643  
   644  func runBenchmarkInterleavedSelect(b *testing.B, db *sqlutils.SQLRunner, count int) {
   645  	defer func() {
   646  		db.Exec(b, `DROP TABLE IF EXISTS bench.interleaved_select2`)
   647  		db.Exec(b, `DROP TABLE IF EXISTS bench.interleaved_select1`)
   648  	}()
   649  
   650  	db.Exec(b, `CREATE TABLE bench.interleaved_select1 (a INT PRIMARY KEY, b INT)`)
   651  	db.Exec(b, `CREATE TABLE bench.interleaved_select2 (c INT PRIMARY KEY, d INT) INTERLEAVE IN PARENT interleaved_select1 (c)`)
   652  
   653  	const interleaveFreq = 4
   654  
   655  	var buf1 bytes.Buffer
   656  	var buf2 bytes.Buffer
   657  	buf1.WriteString(`INSERT INTO bench.interleaved_select1 VALUES `)
   658  	buf2.WriteString(`INSERT INTO bench.interleaved_select2 VALUES `)
   659  	for i := 0; i < count; i++ {
   660  		if i > 0 {
   661  			buf1.WriteString(", ")
   662  		}
   663  		fmt.Fprintf(&buf1, "(%d, %d)", i, i)
   664  		if i%interleaveFreq == 0 {
   665  			if i > 0 {
   666  				buf2.WriteString(", ")
   667  			}
   668  			fmt.Fprintf(&buf2, "(%d, %d)", i, i)
   669  		}
   670  	}
   671  	db.Exec(b, buf1.String())
   672  	db.Exec(b, buf2.String())
   673  
   674  	query := `SELECT * FROM bench.interleaved_select1 is1 INNER JOIN bench.interleaved_select2 is2 on is1.a = is2.c`
   675  
   676  	b.ResetTimer()
   677  	for i := 0; i < b.N; i++ {
   678  		rows := db.Query(b, query)
   679  		n := 0
   680  		for rows.Next() {
   681  			n++
   682  		}
   683  		rows.Close()
   684  		if err := rows.Err(); err != nil {
   685  			b.Fatal(err)
   686  		}
   687  		expected := (count + interleaveFreq - 1) / interleaveFreq
   688  		if n != expected {
   689  			b.Fatalf("unexpected result count: %d (expected %d)", n, expected)
   690  		}
   691  	}
   692  	b.StopTimer()
   693  }
   694  
   695  func runBenchmarkInterleavedFK(b *testing.B, db *sqlutils.SQLRunner, count int) {
   696  	defer func() {
   697  		db.Exec(b, `DROP TABLE IF EXISTS bench.parent CASCADE; DROP TABLE IF EXISTS bench.child CASCADE`)
   698  	}()
   699  
   700  	db.Exec(b, `
   701  CREATE TABLE bench.parent (a INT PRIMARY KEY);
   702  INSERT INTO bench.parent VALUES(0);
   703  CREATE TABLE bench.child
   704    (a INT REFERENCES bench.parent(a),
   705     b INT, PRIMARY KEY(a, b))
   706  INTERLEAVE IN PARENT bench.parent (a)
   707  `)
   708  
   709  	b.ResetTimer()
   710  	var buf bytes.Buffer
   711  	val := 0
   712  	for i := 0; i < b.N; i++ {
   713  		buf.Reset()
   714  		buf.WriteString(`INSERT INTO bench.child VALUES `)
   715  		for j := 0; j < count; j++ {
   716  			if j > 0 {
   717  				buf.WriteString(", ")
   718  			}
   719  			fmt.Fprintf(&buf, "(0, %d)", val)
   720  			val++
   721  		}
   722  		db.Exec(b, buf.String())
   723  	}
   724  }
   725  
   726  // runBenchmarkOrderBy benchmarks scanning a table and sorting the results.
   727  func runBenchmarkOrderBy(
   728  	b *testing.B, db *sqlutils.SQLRunner, count int, limit int, distinct bool,
   729  ) {
   730  	defer func() {
   731  		db.Exec(b, `DROP TABLE IF EXISTS bench.sort`)
   732  	}()
   733  
   734  	db.Exec(b, `CREATE TABLE bench.sort (k INT PRIMARY KEY, v INT, w INT)`)
   735  
   736  	var buf bytes.Buffer
   737  	buf.WriteString(`INSERT INTO bench.sort VALUES `)
   738  	for i := 0; i < count; i++ {
   739  		if i > 0 {
   740  			buf.WriteString(", ")
   741  		}
   742  		fmt.Fprintf(&buf, "(%d, %d, %d)", i, i%(count*4/limit), i%2)
   743  	}
   744  	db.Exec(b, buf.String())
   745  
   746  	var dist string
   747  	if distinct {
   748  		dist = `DISTINCT `
   749  	}
   750  	query := fmt.Sprintf(`SELECT %sv, w, k FROM bench.sort`, dist)
   751  	if limit != 0 {
   752  		query = fmt.Sprintf(`%s ORDER BY v DESC, w ASC, k DESC LIMIT %d`, query, limit)
   753  	}
   754  
   755  	b.ResetTimer()
   756  	for i := 0; i < b.N; i++ {
   757  		rows := db.Query(b, query)
   758  		n := 0
   759  		for rows.Next() {
   760  			n++
   761  		}
   762  		rows.Close()
   763  		if err := rows.Err(); err != nil {
   764  			b.Fatal(err)
   765  		}
   766  		expected := count
   767  		if limit != 0 {
   768  			expected = limit
   769  		}
   770  		if n != expected {
   771  			b.Fatalf("unexpected result count: %d (expected %d)", n, expected)
   772  		}
   773  	}
   774  	b.StopTimer()
   775  }
   776  
   777  func BenchmarkOrderBy(b *testing.B) {
   778  	if testing.Short() {
   779  		b.Skip("short flag")
   780  	}
   781  	defer log.Scope(b).Close(b)
   782  	const count = 100000
   783  	const limit = 10
   784  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
   785  		b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) {
   786  			b.Run(fmt.Sprintf("limit=%d", limit), func(b *testing.B) {
   787  				for _, distinct := range []bool{false, true} {
   788  					b.Run(fmt.Sprintf("distinct=%t", distinct), func(b *testing.B) {
   789  						runBenchmarkOrderBy(b, db, count, limit, distinct)
   790  					})
   791  				}
   792  			})
   793  		})
   794  	})
   795  }
   796  
   797  func runBenchmarkTrackChoices(b *testing.B, db *sqlutils.SQLRunner, batchSize int) {
   798  	defer func() {
   799  		db.Exec(b, `DROP TABLE IF EXISTS bench.track_choices`)
   800  	}()
   801  
   802  	const numOptions = 10000
   803  	// The CREATE INDEX statements are separate in order to be compatible with
   804  	// Postgres.
   805  	const createStmt = `
   806  CREATE TABLE bench.track_choices (
   807    user_id bigint NOT NULL DEFAULT 0,
   808    track_id bigint NOT NULL DEFAULT 0,
   809    created_at timestamp NOT NULL,
   810    PRIMARY KEY (user_id, track_id)
   811  );
   812  CREATE INDEX user_created_at ON bench.track_choices (user_id, created_at);
   813  CREATE INDEX track_created_at ON bench.track_choices (track_id, created_at);
   814  `
   815  	db.Exec(b, createStmt)
   816  
   817  	b.ResetTimer()
   818  	var buf bytes.Buffer
   819  	for i := 0; i < b.N; i += batchSize {
   820  		buf.Reset()
   821  		buf.WriteString(`INSERT INTO bench.track_choices VALUES `)
   822  		count := b.N - i
   823  		if count > batchSize {
   824  			count = batchSize
   825  		}
   826  		for j := 0; j < count; j++ {
   827  			if j > 0 {
   828  				buf.WriteString(", ")
   829  			}
   830  			fmt.Fprintf(&buf, "(%d, %d, now())", rand.Int63(), rand.Int63n(numOptions))
   831  		}
   832  		db.Exec(b, buf.String())
   833  	}
   834  	b.StopTimer()
   835  }
   836  
   837  // Benchmark inserting distinct rows in batches where the min and max rows in
   838  // separate batches overlap. This stresses the spanlatch manager implementation
   839  // and verifies that we're allowing parallel execution of commands where possible.
   840  func runBenchmarkInsertDistinct(b *testing.B, db *sqlutils.SQLRunner, numUsers int) {
   841  	defer func() {
   842  		db.Exec(b, `DROP TABLE IF EXISTS bench.insert_distinct`)
   843  	}()
   844  
   845  	const schema = `
   846  CREATE TABLE bench.insert_distinct (
   847    articleID INT,
   848    userID INT,
   849    uniqueID INT DEFAULT unique_rowid(),
   850    PRIMARY KEY (articleID, userID, uniqueID))
   851  `
   852  	db.Exec(b, schema)
   853  
   854  	b.ResetTimer()
   855  
   856  	errChan := make(chan error)
   857  
   858  	var count int64
   859  	for i := 0; i < numUsers; i++ {
   860  		go func(i int) {
   861  			errChan <- func() error {
   862  				var buf bytes.Buffer
   863  
   864  				rnd := rand.New(rand.NewSource(int64(i)))
   865  				// Article IDs are chosen from a zipf distribution. These values select
   866  				// articleIDs that are mostly <10000. The parameters were experimentally
   867  				// determined, but somewhat arbitrary.
   868  				zipf := rand.NewZipf(rnd, 2, 10000, 100000)
   869  
   870  				for {
   871  					n := atomic.AddInt64(&count, 1)
   872  					if int(n) >= b.N {
   873  						return nil
   874  					}
   875  
   876  					// Insert between [1,100] articles in a batch.
   877  					numArticles := 1 + rnd.Intn(100)
   878  					buf.Reset()
   879  					buf.WriteString(`INSERT INTO bench.insert_distinct VALUES `)
   880  					for j := 0; j < numArticles; j++ {
   881  						if j > 0 {
   882  							buf.WriteString(", ")
   883  						}
   884  						fmt.Fprintf(&buf, "(%d, %d)", zipf.Uint64(), n)
   885  					}
   886  
   887  					if _, err := db.DB.ExecContext(context.Background(), buf.String()); err != nil {
   888  						return err
   889  					}
   890  				}
   891  			}()
   892  		}(i)
   893  	}
   894  
   895  	for i := 0; i < numUsers; i++ {
   896  		if err := <-errChan; err != nil {
   897  			b.Fatal(err)
   898  		}
   899  	}
   900  
   901  	b.StopTimer()
   902  }
   903  
   904  const wideTableSchema = `CREATE TABLE bench.widetable (
   905      f1 INT, f2 INT, f3 INT, f4 INT, f5 INT, f6 INT, f7 INT, f8 INT, f9 INT, f10 INT,
   906      f11 TEXT, f12 TEXT, f13 TEXT, f14 TEXT, f15 TEXT, f16 TEXT, f17 TEXT, f18 TEXT, f19 TEXT,
   907  	f20 TEXT,
   908      PRIMARY KEY (f1, f2, f3)
   909    )`
   910  
   911  func insertIntoWideTable(
   912  	b *testing.B,
   913  	buf bytes.Buffer,
   914  	i, count, bigColumnBytes int,
   915  	s *rand.Rand,
   916  	db *sqlutils.SQLRunner,
   917  ) {
   918  	buf.WriteString(`INSERT INTO bench.widetable VALUES `)
   919  	for j := 0; j < count; j++ {
   920  		if j != 0 {
   921  			if j%3 == 0 {
   922  				buf.WriteString(`;`)
   923  				db.Exec(b, buf.String())
   924  				buf.Reset()
   925  				buf.WriteString(`INSERT INTO bench.widetable VALUES `)
   926  			} else {
   927  				buf.WriteString(`,`)
   928  			}
   929  		}
   930  		buf.WriteString(`(`)
   931  		for k := 0; k < 20; k++ {
   932  			if k != 0 {
   933  				buf.WriteString(`,`)
   934  			}
   935  			if k < 10 {
   936  				fmt.Fprintf(&buf, "%d", i*count+j)
   937  			} else if k < 19 {
   938  				fmt.Fprintf(&buf, "'%d'", i*count+j)
   939  			} else {
   940  				fmt.Fprintf(&buf, "'%x'", randutil.RandBytes(s, bigColumnBytes))
   941  			}
   942  		}
   943  		buf.WriteString(`)`)
   944  	}
   945  	buf.WriteString(`;`)
   946  	db.Exec(b, buf.String())
   947  	buf.Reset()
   948  }
   949  
   950  // runBenchmarkWideTable measures performance on a table with a large number of
   951  // columns (20), half of which are fixed size, half of which are variable sized
   952  // and presumed small. 1 of the presumed small columns is actually large.
   953  //
   954  // This benchmark tracks the tradeoff in column family allocation at table
   955  // creation. Fewer column families mean fewer kv entries, which is faster. But
   956  // fewer column families mean updates are less targeted, which means large
   957  // columns in a family may be copied unnecessarily when it's updated. Perfect
   958  // knowledge of traffic patterns can result in much better heuristics, but we
   959  // don't have that information at table creation.
   960  func runBenchmarkWideTable(b *testing.B, db *sqlutils.SQLRunner, count int, bigColumnBytes int) {
   961  	defer func() {
   962  		db.Exec(b, `DROP TABLE IF EXISTS bench.widetable`)
   963  	}()
   964  
   965  	db.Exec(b, wideTableSchema)
   966  
   967  	s := rand.New(rand.NewSource(5432))
   968  
   969  	var buf bytes.Buffer
   970  
   971  	b.ResetTimer()
   972  	for i := 0; i < b.N; i++ {
   973  		buf.Reset()
   974  
   975  		insertIntoWideTable(b, buf, i, count, bigColumnBytes, s, db)
   976  
   977  		// These are all updates, but ON CONFLICT DO UPDATE is (much!) faster
   978  		// because it can do blind writes.
   979  		buf.WriteString(`INSERT INTO bench.widetable (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) VALUES `)
   980  		for j := 0; j < count; j++ {
   981  			if j != 0 {
   982  				buf.WriteString(`,`)
   983  			}
   984  			fmt.Fprintf(&buf, `(%d,%d,%d,`, i*count+j, i*count+j, i*count+j)
   985  			for k := 0; k < 7; k++ {
   986  				if k != 0 {
   987  					buf.WriteString(`,`)
   988  				}
   989  				fmt.Fprintf(&buf, "%d", s.Intn(j+1))
   990  			}
   991  			buf.WriteString(`)`)
   992  		}
   993  		buf.WriteString(`ON CONFLICT (f1,f2,f3) DO UPDATE SET f4=excluded.f4,f5=excluded.f5,f6=excluded.f6,f7=excluded.f7,f8=excluded.f8,f9=excluded.f9,f10=excluded.f10;`)
   994  
   995  		buf.WriteString(`DELETE FROM bench.widetable WHERE f1 in (`)
   996  		for j := 0; j < count; j++ {
   997  			if j != 0 {
   998  				buf.WriteString(`,`)
   999  			}
  1000  			fmt.Fprintf(&buf, "%d", j)
  1001  		}
  1002  		buf.WriteString(`);`)
  1003  
  1004  		db.Exec(b, buf.String())
  1005  	}
  1006  	b.StopTimer()
  1007  }
  1008  
  1009  // BenchmarkVecSkipScan benchmarks the vectorized engine's performance
  1010  // when skipping unneeded key values in the decoding process.
  1011  func BenchmarkVecSkipScan(b *testing.B) {
  1012  	benchmarkCockroach(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1013  		create := `
  1014  CREATE TABLE bench.scan(
  1015  	x INT, y INT, z INT, 
  1016  	a INT, w INT, v INT, 
  1017  	PRIMARY KEY (x, y, z, a, w, v)
  1018  )
  1019  `
  1020  		db.Exec(b, create)
  1021  		const count = 1000
  1022  		for i := 0; i < count; i++ {
  1023  			db.Exec(
  1024  				b,
  1025  				fmt.Sprintf(
  1026  					"INSERT INTO bench.scan VALUES (%d, %d, %d, %d, %d, %d)",
  1027  					i, i, i, i, i, i,
  1028  				),
  1029  			)
  1030  		}
  1031  		b.ResetTimer()
  1032  		b.Run("Bench scan with skip", func(b *testing.B) {
  1033  			for i := 0; i < b.N; i++ {
  1034  				db.Exec(b, `SET vectorize=on; SELECT y FROM bench.scan`)
  1035  			}
  1036  		})
  1037  	})
  1038  }
  1039  
  1040  func BenchmarkWideTable(b *testing.B) {
  1041  	if testing.Short() {
  1042  		b.Skip("short flag")
  1043  	}
  1044  	defer log.Scope(b).Close(b)
  1045  	const count = 10
  1046  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1047  		b.Run(fmt.Sprintf("count=%d", count), func(b *testing.B) {
  1048  			for _, bigColumnBytes := range []int{10, 100, 1000, 10000, 100000, 1000000} {
  1049  				b.Run(fmt.Sprintf("bigColumnBytes=%d", bigColumnBytes), func(b *testing.B) {
  1050  					runBenchmarkWideTable(b, db, count, bigColumnBytes)
  1051  				})
  1052  			}
  1053  		})
  1054  	})
  1055  }
  1056  
  1057  func BenchmarkWideTableIgnoreColumns(b *testing.B) {
  1058  	if testing.Short() {
  1059  		b.Skip("short flag")
  1060  	}
  1061  	defer log.Scope(b).Close(b)
  1062  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1063  		db.Exec(b, wideTableSchema)
  1064  		var buf bytes.Buffer
  1065  		s := rand.New(rand.NewSource(5432))
  1066  		insertIntoWideTable(b, buf, 0, 10000, 10, s, db)
  1067  
  1068  		b.ResetTimer()
  1069  
  1070  		for i := 0; i < b.N; i++ {
  1071  			db.Exec(b, "SELECT count(*) FROM bench.widetable WHERE f4 < 10")
  1072  		}
  1073  	})
  1074  }
  1075  
  1076  // BenchmarkPlanning runs some queries on an empty table. The purpose is to
  1077  // benchmark (and get memory allocation statistics for) the planning process.
  1078  func BenchmarkPlanning(b *testing.B) {
  1079  	if testing.Short() {
  1080  		b.Skip("short flag")
  1081  	}
  1082  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1083  		db.Exec(b, `CREATE TABLE abc (a INT PRIMARY KEY, b INT, c INT, INDEX(b), UNIQUE INDEX(c))`)
  1084  
  1085  		queries := []string{
  1086  			`SELECT * FROM abc`,
  1087  			`SELECT * FROM abc WHERE a > 5 ORDER BY a`,
  1088  			`SELECT * FROM abc WHERE b = 5`,
  1089  			`SELECT * FROM abc WHERE b = 5 ORDER BY a`,
  1090  			`SELECT * FROM abc WHERE c = 5`,
  1091  			`SELECT * FROM abc JOIN abc AS abc2 ON abc.a = abc2.a`,
  1092  		}
  1093  		for _, q := range queries {
  1094  			b.Run(q, func(b *testing.B) {
  1095  				for i := 0; i < b.N; i++ {
  1096  					db.Exec(b, q)
  1097  				}
  1098  			})
  1099  		}
  1100  	})
  1101  }
  1102  
  1103  // BenchmarkIndexJoin measure an index-join with 1000 rows.
  1104  func BenchmarkIndexJoin(b *testing.B) {
  1105  	defer log.Scope(b).Close(b)
  1106  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1107  		// The table will have an extra column not contained in the index to force a
  1108  		// join with the PK.
  1109  		create := `
  1110  		 CREATE TABLE tidx (
  1111  				 k INT NOT NULL,
  1112  				 v INT NULL,
  1113  				 extra STRING NULL,
  1114  				 CONSTRAINT "primary" PRIMARY KEY (k ASC),
  1115  				 INDEX idx (v ASC),
  1116  				 FAMILY "primary" (k, v, extra)
  1117  		 )
  1118  		`
  1119  		// We'll insert 1000 rows with random values below 1000 in the index. We'll
  1120  		// then query the index with a query that retrieves all the data (but the
  1121  		// optimizer doesn't know that).
  1122  		insert := "insert into tidx(k,v) select generate_series(1,1000), (random()*1000)::int"
  1123  
  1124  		db.Exec(b, create)
  1125  		db.Exec(b, insert)
  1126  		b.ResetTimer()
  1127  
  1128  		for i := 0; i < b.N; i++ {
  1129  			db.Exec(b, "select * from bench.tidx where v < 1000")
  1130  		}
  1131  	})
  1132  }
  1133  
  1134  func BenchmarkSortJoinAggregation(b *testing.B) {
  1135  	defer log.Scope(b).Close(b)
  1136  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1137  		tables := []struct {
  1138  			create   string
  1139  			populate string
  1140  		}{
  1141  			{
  1142  				create: `
  1143  				 CREATE TABLE abc (
  1144  					 a INT PRIMARY KEY,
  1145  					 b INT,
  1146  					 c FLOAT
  1147  				 )`,
  1148  				populate: `
  1149  				 INSERT INTO abc SELECT generate_series(1,1000), (random()*1000)::int, random()::float`,
  1150  			},
  1151  			{
  1152  				create: `
  1153  				 CREATE TABLE xyz (
  1154  					 x INT PRIMARY KEY,
  1155  					 y INT,
  1156  					 z FLOAT
  1157  				 )`,
  1158  				populate: `
  1159  				 INSERT INTO xyz SELECT generate_series(1,1000), (random()*1000)::int, random()::float`,
  1160  			},
  1161  		}
  1162  
  1163  		for _, table := range tables {
  1164  			db.Exec(b, table.create)
  1165  			db.Exec(b, table.populate)
  1166  		}
  1167  
  1168  		query := `
  1169  			SELECT b, count(*) FROM
  1170  				(SELECT b, avg(c) FROM (SELECT b, c FROM abc ORDER BY b) GROUP BY b)
  1171  				JOIN
  1172  				(SELECT y, sum(z) FROM (SELECT y, z FROM xyz ORDER BY y) GROUP BY y)
  1173  				ON b = y
  1174  			GROUP BY b
  1175  			ORDER BY b`
  1176  
  1177  		b.ResetTimer()
  1178  		for i := 0; i < b.N; i++ {
  1179  			db.Exec(b, query)
  1180  		}
  1181  	})
  1182  }
  1183  
  1184  func BenchmarkNameResolution(b *testing.B) {
  1185  	if testing.Short() {
  1186  		b.Skip("short flag")
  1187  	}
  1188  	defer log.Scope(b).Close(b)
  1189  	ForEachDB(b, func(b *testing.B, db *sqlutils.SQLRunner) {
  1190  		db.Exec(b, `CREATE TABLE namespace (k INT PRIMARY KEY, v INT)`)
  1191  		db.Exec(b, `INSERT INTO namespace VALUES(1, 2)`)
  1192  
  1193  		b.ResetTimer()
  1194  
  1195  		for i := 0; i < b.N; i++ {
  1196  			db.Exec(b, "SELECT * FROM namespace")
  1197  		}
  1198  		b.StopTimer()
  1199  	})
  1200  }