github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-sql-driver/mysql/benchmark_test.go (about) 1 // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 // 3 // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 // 5 // This Source Code Form is subject to the terms of the Mozilla Public 6 // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 // You can obtain one at http://mozilla.org/MPL/2.0/. 8 9 package mysql 10 11 import ( 12 "bytes" 13 "database/sql" 14 "database/sql/driver" 15 "math" 16 "strings" 17 "sync" 18 "sync/atomic" 19 "testing" 20 "time" 21 ) 22 23 type TB testing.B 24 25 func (tb *TB) check(err error) { 26 if err != nil { 27 tb.Fatal(err) 28 } 29 } 30 31 func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB { 32 tb.check(err) 33 return db 34 } 35 36 func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows { 37 tb.check(err) 38 return rows 39 } 40 41 func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt { 42 tb.check(err) 43 return stmt 44 } 45 46 func initDB(b *testing.B, queries ...string) *sql.DB { 47 tb := (*TB)(b) 48 db := tb.checkDB(sql.Open("mysql", dsn)) 49 for _, query := range queries { 50 if _, err := db.Exec(query); err != nil { 51 if w, ok := err.(MySQLWarnings); ok { 52 b.Logf("warning on %q: %v", query, w) 53 } else { 54 b.Fatalf("error on %q: %v", query, err) 55 } 56 } 57 } 58 return db 59 } 60 61 const concurrencyLevel = 10 62 63 func BenchmarkQuery(b *testing.B) { 64 tb := (*TB)(b) 65 b.StopTimer() 66 b.ReportAllocs() 67 db := initDB(b, 68 "DROP TABLE IF EXISTS foo", 69 "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", 70 `INSERT INTO foo VALUES (1, "one")`, 71 `INSERT INTO foo VALUES (2, "two")`, 72 ) 73 db.SetMaxIdleConns(concurrencyLevel) 74 defer db.Close() 75 76 stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?")) 77 defer stmt.Close() 78 79 remain := int64(b.N) 80 var wg sync.WaitGroup 81 wg.Add(concurrencyLevel) 82 defer wg.Wait() 83 b.StartTimer() 84 85 for i := 0; i < concurrencyLevel; i++ { 86 go func() { 87 for { 88 if atomic.AddInt64(&remain, -1) < 0 { 89 wg.Done() 90 return 91 } 92 93 var got string 94 tb.check(stmt.QueryRow(1).Scan(&got)) 95 if got != "one" { 96 b.Errorf("query = %q; want one", got) 97 wg.Done() 98 return 99 } 100 } 101 }() 102 } 103 } 104 105 func BenchmarkExec(b *testing.B) { 106 tb := (*TB)(b) 107 b.StopTimer() 108 b.ReportAllocs() 109 db := tb.checkDB(sql.Open("mysql", dsn)) 110 db.SetMaxIdleConns(concurrencyLevel) 111 defer db.Close() 112 113 stmt := tb.checkStmt(db.Prepare("DO 1")) 114 defer stmt.Close() 115 116 remain := int64(b.N) 117 var wg sync.WaitGroup 118 wg.Add(concurrencyLevel) 119 defer wg.Wait() 120 b.StartTimer() 121 122 for i := 0; i < concurrencyLevel; i++ { 123 go func() { 124 for { 125 if atomic.AddInt64(&remain, -1) < 0 { 126 wg.Done() 127 return 128 } 129 130 if _, err := stmt.Exec(); err != nil { 131 b.Fatal(err.Error()) 132 } 133 } 134 }() 135 } 136 } 137 138 // data, but no db writes 139 var roundtripSample []byte 140 141 func initRoundtripBenchmarks() ([]byte, int, int) { 142 if roundtripSample == nil { 143 roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024)) 144 } 145 return roundtripSample, 16, len(roundtripSample) 146 } 147 148 func BenchmarkRoundtripTxt(b *testing.B) { 149 b.StopTimer() 150 sample, min, max := initRoundtripBenchmarks() 151 sampleString := string(sample) 152 b.ReportAllocs() 153 tb := (*TB)(b) 154 db := tb.checkDB(sql.Open("mysql", dsn)) 155 defer db.Close() 156 b.StartTimer() 157 var result string 158 for i := 0; i < b.N; i++ { 159 length := min + i 160 if length > max { 161 length = max 162 } 163 test := sampleString[0:length] 164 rows := tb.checkRows(db.Query(`SELECT "` + test + `"`)) 165 if !rows.Next() { 166 rows.Close() 167 b.Fatalf("crashed") 168 } 169 err := rows.Scan(&result) 170 if err != nil { 171 rows.Close() 172 b.Fatalf("crashed") 173 } 174 if result != test { 175 rows.Close() 176 b.Errorf("mismatch") 177 } 178 rows.Close() 179 } 180 } 181 182 func BenchmarkRoundtripBin(b *testing.B) { 183 b.StopTimer() 184 sample, min, max := initRoundtripBenchmarks() 185 b.ReportAllocs() 186 tb := (*TB)(b) 187 db := tb.checkDB(sql.Open("mysql", dsn)) 188 defer db.Close() 189 stmt := tb.checkStmt(db.Prepare("SELECT ?")) 190 defer stmt.Close() 191 b.StartTimer() 192 var result sql.RawBytes 193 for i := 0; i < b.N; i++ { 194 length := min + i 195 if length > max { 196 length = max 197 } 198 test := sample[0:length] 199 rows := tb.checkRows(stmt.Query(test)) 200 if !rows.Next() { 201 rows.Close() 202 b.Fatalf("crashed") 203 } 204 err := rows.Scan(&result) 205 if err != nil { 206 rows.Close() 207 b.Fatalf("crashed") 208 } 209 if !bytes.Equal(result, test) { 210 rows.Close() 211 b.Errorf("mismatch") 212 } 213 rows.Close() 214 } 215 } 216 217 func BenchmarkInterpolation(b *testing.B) { 218 mc := &mysqlConn{ 219 cfg: &Config{ 220 InterpolateParams: true, 221 Loc: time.UTC, 222 }, 223 maxPacketAllowed: maxPacketSize, 224 maxWriteSize: maxPacketSize - 1, 225 buf: newBuffer(nil), 226 } 227 228 args := []driver.Value{ 229 int64(42424242), 230 float64(math.Pi), 231 false, 232 time.Unix(1423411542, 807015000), 233 []byte("bytes containing special chars ' \" \a \x00"), 234 "string containing special chars ' \" \a \x00", 235 } 236 q := "SELECT ?, ?, ?, ?, ?, ?" 237 238 b.ReportAllocs() 239 b.ResetTimer() 240 for i := 0; i < b.N; i++ { 241 _, err := mc.interpolateParams(q, args) 242 if err != nil { 243 b.Fatal(err) 244 } 245 } 246 }