@@ -46,10 +46,10 @@ func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
46
46
return stmt
47
47
}
48
48
49
- func initDB (b * testing.B , useCompression bool , queries ... string ) * sql.DB {
49
+ func initDB (b * testing.B , compress bool , queries ... string ) * sql.DB {
50
50
tb := (* TB )(b )
51
51
comprStr := ""
52
- if useCompression {
52
+ if compress {
53
53
comprStr = "&compress=1"
54
54
}
55
55
db := tb .checkDB (sql .Open (driverNameTest , dsn + comprStr ))
@@ -64,16 +64,15 @@ func initDB(b *testing.B, useCompression bool, queries ...string) *sql.DB {
64
64
const concurrencyLevel = 10
65
65
66
66
func BenchmarkQuery (b * testing.B ) {
67
- benchmarkQueryHelper (b , false )
67
+ benchmarkQuery (b , false )
68
68
}
69
69
70
- func BenchmarkQueryCompression (b * testing.B ) {
71
- benchmarkQueryHelper (b , true )
70
+ func BenchmarkQueryCompressed (b * testing.B ) {
71
+ benchmarkQuery (b , true )
72
72
}
73
73
74
- func benchmarkQueryHelper (b * testing.B , compr bool ) {
74
+ func benchmarkQuery (b * testing.B , compr bool ) {
75
75
tb := (* TB )(b )
76
- b .StopTimer ()
77
76
b .ReportAllocs ()
78
77
db := initDB (b , compr ,
79
78
"DROP TABLE IF EXISTS foo" ,
@@ -93,7 +92,7 @@ func benchmarkQueryHelper(b *testing.B, compr bool) {
93
92
defer wg .Wait ()
94
93
b .StartTimer ()
95
94
96
- for range concurrencyLevel {
95
+ for i := 0 ; i < concurrencyLevel ; i ++ {
97
96
go func () {
98
97
for {
99
98
if atomic .AddInt64 (& remain , - 1 ) < 0 {
@@ -115,8 +114,6 @@ func benchmarkQueryHelper(b *testing.B, compr bool) {
115
114
116
115
func BenchmarkExec (b * testing.B ) {
117
116
tb := (* TB )(b )
118
- b .StopTimer ()
119
- b .ReportAllocs ()
120
117
db := tb .checkDB (sql .Open (driverNameTest , dsn ))
121
118
db .SetMaxIdleConns (concurrencyLevel )
122
119
defer db .Close ()
@@ -128,9 +125,11 @@ func BenchmarkExec(b *testing.B) {
128
125
var wg sync.WaitGroup
129
126
wg .Add (concurrencyLevel )
130
127
defer wg .Wait ()
131
- b .StartTimer ()
132
128
133
- for range concurrencyLevel {
129
+ b .ReportAllocs ()
130
+ b .ResetTimer ()
131
+
132
+ for i := 0 ; i < concurrencyLevel ; i ++ {
134
133
go func () {
135
134
for {
136
135
if atomic .AddInt64 (& remain , - 1 ) < 0 {
@@ -158,14 +157,15 @@ func initRoundtripBenchmarks() ([]byte, int, int) {
158
157
}
159
158
160
159
func BenchmarkRoundtripTxt (b * testing.B ) {
161
- b .StopTimer ()
162
160
sample , min , max := initRoundtripBenchmarks ()
163
161
sampleString := string (sample )
164
- b .ReportAllocs ()
165
162
tb := (* TB )(b )
166
163
db := tb .checkDB (sql .Open (driverNameTest , dsn ))
167
164
defer db .Close ()
168
- b .StartTimer ()
165
+
166
+ b .ReportAllocs ()
167
+ b .ResetTimer ()
168
+
169
169
var result string
170
170
for i := 0 ; i < b .N ; i ++ {
171
171
length := min + i
@@ -192,15 +192,15 @@ func BenchmarkRoundtripTxt(b *testing.B) {
192
192
}
193
193
194
194
func BenchmarkRoundtripBin (b * testing.B ) {
195
- b .StopTimer ()
196
195
sample , min , max := initRoundtripBenchmarks ()
197
- b .ReportAllocs ()
198
196
tb := (* TB )(b )
199
197
db := tb .checkDB (sql .Open (driverNameTest , dsn ))
200
198
defer db .Close ()
201
199
stmt := tb .checkStmt (db .Prepare ("SELECT ?" ))
202
200
defer stmt .Close ()
203
- b .StartTimer ()
201
+
202
+ b .ReportAllocs ()
203
+ b .ResetTimer ()
204
204
var result sql.RawBytes
205
205
for i := 0 ; i < b .N ; i ++ {
206
206
length := min + i
@@ -345,7 +345,7 @@ func BenchmarkQueryRawBytes(b *testing.B) {
345
345
for i := range blob {
346
346
blob [i ] = 42
347
347
}
348
- for i := range 100 {
348
+ for i := 0 ; i < 100 ; i ++ {
349
349
_ , err := db .Exec ("INSERT INTO bench_rawbytes VALUES (?, ?)" , i , blob )
350
350
if err != nil {
351
351
b .Fatal (err )
@@ -385,10 +385,9 @@ func BenchmarkQueryRawBytes(b *testing.B) {
385
385
}
386
386
}
387
387
388
- // BenchmarkReceiveMassiveRows measures performance of receiving large number of rows.
389
- func BenchmarkReceiveMassiveRows (b * testing.B ) {
388
+ func benchmark10kRows (b * testing.B , compress bool ) {
390
389
// Setup -- prepare 10000 rows.
391
- db := initDB (b , false ,
390
+ db := initDB (b , compress ,
392
391
"DROP TABLE IF EXISTS foo" ,
393
392
"CREATE TABLE foo (id INT PRIMARY KEY, val TEXT)" )
394
393
defer db .Close ()
@@ -399,11 +398,14 @@ func BenchmarkReceiveMassiveRows(b *testing.B) {
399
398
b .Errorf ("failed to prepare query: %v" , err )
400
399
return
401
400
}
401
+
402
+ args := make ([]any , 200 )
403
+ for i := 1 ; i < 200 ; i += 2 {
404
+ args [i ] = sval
405
+ }
402
406
for i := 0 ; i < 10000 ; i += 100 {
403
- args := make ([]any , 200 )
404
- for j := range 100 {
407
+ for j := 0 ; j < 100 ; j ++ {
405
408
args [j * 2 ] = i + j
406
- args [j * 2 + 1 ] = sval
407
409
}
408
410
_ , err := stmt .Exec (args ... )
409
411
if err != nil {
@@ -413,30 +415,43 @@ func BenchmarkReceiveMassiveRows(b *testing.B) {
413
415
}
414
416
stmt .Close ()
415
417
416
- // Use b.Run() to skip expensive setup.
418
+ // benchmark function called several times with different b.N.
419
+ // it means heavy setup is called multiple times.
420
+ // Use b.Run() to run expensive setup only once.
421
+ // Go 1.24 introduced b.Loop() for this purpose. But we keep this
422
+ // benchmark compatible with Go 1.20.
417
423
b .Run ("query" , func (b * testing.B ) {
418
424
b .ReportAllocs ()
419
-
420
425
for i := 0 ; i < b .N ; i ++ {
421
426
rows , err := db .Query (`SELECT id, val FROM foo` )
422
427
if err != nil {
423
428
b .Errorf ("failed to select: %v" , err )
424
429
return
425
430
}
431
+ // rows.Scan() escapes arguments. So these variables must be defined
432
+ // before loop.
433
+ var i int
434
+ var s sql.RawBytes
426
435
for rows .Next () {
427
- var i int
428
- var s sql.RawBytes
429
- err = rows .Scan (& i , & s )
430
- if err != nil {
436
+ if err := rows .Scan (& i , & s ); err != nil {
431
437
b .Errorf ("failed to scan: %v" , err )
432
- _ = rows .Close ()
438
+ rows .Close ()
433
439
return
434
440
}
435
441
}
436
442
if err = rows .Err (); err != nil {
437
443
b .Errorf ("failed to read rows: %v" , err )
438
444
}
439
- _ = rows .Close ()
445
+ rows .Close ()
440
446
}
441
447
})
442
448
}
449
+
450
+ // BenchmarkReceive10kRows measures performance of receiving large number of rows.
451
+ func BenchmarkReceive10kRows (b * testing.B ) {
452
+ benchmark10kRows (b , false )
453
+ }
454
+
455
+ func BenchmarkReceive10kRowsCompressed (b * testing.B ) {
456
+ benchmark10kRows (b , true )
457
+ }
0 commit comments