mirror of
https://gitlab.com/cznic/sqlite.git
synced 2025-04-27 23:07:44 +00:00
377 lines
9.2 KiB
Go
377 lines
9.2 KiB
Go
// Copyright 2021 The Sqlite Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
package benchmark
|
|
|
|
/*
|
|
this file contains benchmarks inspired by https://www.sqlite.org/speed.html
|
|
*/
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"math/rand"
|
|
"testing"
|
|
)
|
|
|
|
// corresponds to Test 1 from https://www.sqlite.org/speed.html
|
|
func benchInsert(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// measure from here
|
|
b.ResetTimer()
|
|
|
|
fillTestTable(db, b.N)
|
|
}
|
|
|
|
// corresponds to Test 2 from https://www.sqlite.org/speed.html
|
|
func benchInsertInTransaction(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// measure from here
|
|
b.ResetTimer()
|
|
|
|
fillTestTableInTx(db, b.N)
|
|
}
|
|
|
|
// corresponds to Test 3 from https://www.sqlite.org/speed.html
|
|
func benchInsertIntoIndexed(b *testing.B, db *sql.DB) {
|
|
// create test table with indexed column
|
|
createTestTable(db, `c`)
|
|
|
|
b.ResetTimer()
|
|
|
|
fillTestTableInTx(db, b.N)
|
|
}
|
|
|
|
// corresponds to Test 4 from https://www.sqlite.org/speed.html
|
|
func benchSelectWithoutIndex(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// prepare statement for selection
|
|
stmt, err := db.Prepare(fmt.Sprintf(`SELECT count(*), avg(b) FROM %s WHERE b>=? AND b<?`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
// exec many selects
|
|
// SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<1000;
|
|
// SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<1100;
|
|
// SELECT count(*), avg(b) FROM t2 WHERE b>=200 AND b<1200;
|
|
// ...
|
|
for i := 0; i < b.N; i++ {
|
|
b := (i * 100) % maxGeneratedNum
|
|
if _, err := stmt.Exec(b, b+1000); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// corresponds to Test 5 from https://www.sqlite.org/speed.html
|
|
func benchSelectOnStringComparison(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// prepare statement for selection
|
|
stmt, err := db.Prepare(fmt.Sprintf(`SELECT count(*), avg(b) FROM %s WHERE c LIKE ?`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
// exec many selects
|
|
// SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%one%';
|
|
// SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%two%';
|
|
// ...
|
|
// SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%ninety nine%';
|
|
for i := 1; i <= b.N; i++ {
|
|
// e.g. following will produce "... WHERE c LIKE '%seventy eight%' "
|
|
likeCond := pronounceNum(uint32(i) % 100)
|
|
if _, err := stmt.Exec(`%` + likeCond + `%`); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// corresponds to Test 6 from https://www.sqlite.org/speed.html
|
|
func benchCreateIndex(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
var (
|
|
nameIdxA = "iA"
|
|
nameIdxB = "iB"
|
|
createIndStmtA = fmt.Sprintf(`CREATE INDEX %s ON %s(a)`, nameIdxA, testTableName)
|
|
createIndStmtB = fmt.Sprintf(`CREATE INDEX %s ON %s(c)`, nameIdxB, testTableName)
|
|
dropIndStmtA = fmt.Sprintf(`DROP INDEX IF EXISTS %s`, nameIdxA)
|
|
dropIndStmtB = fmt.Sprintf(`DROP INDEX IF EXISTS %s`, nameIdxB)
|
|
)
|
|
|
|
b.ResetTimer()
|
|
for i := 1; i <= b.N; i++ {
|
|
// drop indexes from previous iteration (if any)
|
|
b.StopTimer()
|
|
mustExec(db, dropIndStmtA, dropIndStmtB)
|
|
b.StartTimer()
|
|
|
|
// create indexes
|
|
runInTransaction(db, func() {
|
|
mustExec(db, createIndStmtA, createIndStmtB)
|
|
})
|
|
}
|
|
}
|
|
|
|
// corresponds to Test 7 from https://www.sqlite.org/speed.html
|
|
func benchSelectWithIndex(b *testing.B, db *sql.DB) {
|
|
// create test table with indexed field
|
|
createTestTable(db, `b`)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// prepare statement for selection
|
|
stmt, err := db.Prepare(fmt.Sprintf(`SELECT count(*), avg(b) FROM %s WHERE b>=? AND b<?`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
// exec many selects
|
|
// SELECT count(*), avg(b) FROM t2 WHERE b>=0 AND b<100;
|
|
// SELECT count(*), avg(b) FROM t2 WHERE b>=100 AND b<200;
|
|
// SELECT count(*), avg(b) FROM t2 WHERE b>=200 AND b<300;
|
|
for i := 0; i < b.N; i++ {
|
|
b := (i * 100) % maxGeneratedNum
|
|
if _, err := stmt.Exec(b, b+100); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
// corresponds to Test 8 from https://www.sqlite.org/speed.html
|
|
func benchUpdateWithoutIndex(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// prepare statement
|
|
stmt, err := db.Prepare(fmt.Sprintf(`UPDATE %s SET b=b*2 WHERE a>=? AND a<?`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
// exec many
|
|
// UPDATE t1 SET b=b*2 WHERE a>=0 AND a<10;
|
|
// UPDATE t1 SET b=b*2 WHERE a>=10 AND a<20;
|
|
// UPDATE t1 SET b=b*2 WHERE a>=20 AND a<30;
|
|
for i := 0; i < b.N; i++ {
|
|
a := (i * 10) % testTableRowCount
|
|
if _, err := stmt.Exec(a, a+10); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
|
|
}
|
|
|
|
// corresponds to Test 9 from https://www.sqlite.org/speed.html
|
|
func benchUpdateWithIndex(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db, `a`)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// prepare statement
|
|
stmt, err := db.Prepare(fmt.Sprintf(`UPDATE %s SET b=? WHERE a=?`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
// exec many
|
|
// UPDATE t2 SET b=468026 WHERE a=1;
|
|
// UPDATE t2 SET b=121928 WHERE a=2;
|
|
// ...
|
|
for i := 0; i < b.N; i++ {
|
|
if _, err := stmt.Exec(
|
|
rand.Uint32(), // b = ?
|
|
i%testTableRowCount+1, // WHERE a=?
|
|
); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// corresponds to Test 10 from https://www.sqlite.org/speed.html
|
|
func benchUpdateTextWithIndex(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db, `a`)
|
|
|
|
// fill test table
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// prepare statement
|
|
stmt, err := db.Prepare(fmt.Sprintf(`UPDATE %s SET c=? WHERE a=?`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
// exec many
|
|
// UPDATE t2 SET c='one hundred forty eight thousand three hundred eighty two' WHERE a=1;
|
|
// UPDATE t2 SET c='three hundred sixty six thousand five hundred two' WHERE a=2;
|
|
for i := 0; i < b.N; i++ {
|
|
// generate new random number-as-words for c
|
|
if _, err := stmt.Exec(
|
|
pronounceNum(uint32(rand.Int31n(maxGeneratedNum))), // SET c=?
|
|
i%testTableRowCount+1, // WHERE a=?
|
|
); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// corresponds to Test 11 from https://www.sqlite.org/speed.html
|
|
func benchInsertFromSelect(b *testing.B, db *sql.DB) {
|
|
// create source table
|
|
createTestTable(db)
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
|
|
// create name for target table
|
|
targetTableName := fmt.Sprintf("%s_copy", testTableName)
|
|
|
|
// need to create table here, otherwise prepared statement will give error
|
|
createTestTableWithName(db, targetTableName)
|
|
|
|
// prepare statement
|
|
stmt, err := db.Prepare(fmt.Sprintf(`INSERT INTO %s SELECT b,a,c FROM %s`, targetTableName, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
// drop/create target table
|
|
b.StopTimer()
|
|
createTestTableWithName(db, targetTableName)
|
|
b.StartTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
if _, err := stmt.Exec(); err != nil {
|
|
panic(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// corresponds to Test 12 from https://www.sqlite.org/speed.html
|
|
func benchDeleteWithoutIndex(b *testing.B, db *sql.DB) {
|
|
// create test table
|
|
createTestTable(db)
|
|
|
|
// prepare statement for deletion
|
|
stmt, err := db.Prepare(fmt.Sprintf(`DELETE FROM %s WHERE c LIKE '%%fifty%%'`, testTableName))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
// drop/create target table
|
|
b.StopTimer()
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
b.StartTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
if _, err := stmt.Exec(); err != nil {
|
|
panic(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// corresponds to Test 13 from https://www.sqlite.org/speed.html
|
|
func benchDeleteWithIndex(b *testing.B, db *sql.DB) {
|
|
// create test table with indexed column
|
|
createTestTable(db, `a`)
|
|
|
|
// prepare statement for BIG deletion (nearly half of table rows)
|
|
stmt, err := db.Prepare(fmt.Sprintf(`DELETE FROM %s WHERE a>%d AND a<%d`, testTableName, 10, testTableRowCount/2))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stmt.Close()
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
// drop/create target table
|
|
b.StopTimer()
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
b.StartTimer()
|
|
|
|
runInTransaction(db, func() {
|
|
if _, err := stmt.Exec(); err != nil {
|
|
panic(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// corresponds to Test 16 from https://www.sqlite.org/speed.html
|
|
func benchDropTable(b *testing.B, db *sql.DB) {
|
|
for i := 0; i < b.N; i++ {
|
|
b.StopTimer()
|
|
createTestTable(db)
|
|
fillTestTableInTx(db, testTableRowCount)
|
|
b.StartTimer()
|
|
|
|
if _, err := db.Exec(fmt.Sprintf("DROP TABLE %s", testTableName)); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|