Add a Benchmark comparing us with the sqlx package

pull/2/head
Vinícius Garcia 2021-01-22 21:25:14 -03:00
parent f655576bb3
commit e1e711dc91
6 changed files with 265 additions and 1 deletions

View File

@ -3,9 +3,14 @@ path=./...
GOPATH=$(shell go env GOPATH)
TIME=1s
test: setup
$(GOPATH)/bin/richgo test $(path) $(args)
bench:
go test -bench=. -benchtime=$(TIME)
lint: setup
@$(GOPATH)/bin/golint -set_exit_status -min_confidence 0.9 $(path) $(args)
@go vet $(path) $(args)

View File

@ -21,6 +21,8 @@ Currently we only support 2 Drivers:
### Why KissORM?
> Note: If you want numbers see our Benchmark section below
KissORM was created to fill a hole between the complexity
we find in the tools I've seen so far, namely:
@ -200,6 +202,26 @@ This library has a few helper functions for helping your tests:
If you want to see examples (we have examples for all the public functions) just
read the example tests available on our [example service](./examples/example_service)
### Benchmark Comparison
The benchmark is not bad, as far the code is in average as fast as sqlx:
```bash
$ make bench TIME=3s
go test -bench=. -benchtime=3s
goos: linux
goarch: amd64
pkg: github.com/vingarcia/kissorm
BenchmarkInsert/kissorm-setup/insert-one-4 4306 880132 ns/op
BenchmarkInsert/sqlx-setup/insert-one-4 4573 792488 ns/op
BenchmarkQuery/kissorm-setup/single-row-4 10000 315328 ns/op
BenchmarkQuery/kissorm-setup/multiple-rows-4 9288 388538 ns/op
BenchmarkQuery/sqlx-setup/single-row-4 10000 323424 ns/op
BenchmarkQuery/sqlx-setup/multiple-rows-4 10000 338570 ns/op
PASS
ok github.com/vingarcia/kissorm 21.740s
```
### TODO List
- Allow the ID field to have a different name

232
benchmark_test.go Normal file
View File

@ -0,0 +1,232 @@
package kissorm_test
import (
"context"
"database/sql"
"fmt"
"strconv"
"testing"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"github.com/vingarcia/kissorm"
)
func BenchmarkInsert(b *testing.B) {
ctx := context.Background()
driver := "postgres"
connStr := "host=localhost port=5432 user=postgres password=postgres dbname=kissorm sslmode=disable"
kissormDB, err := kissorm.New(driver, connStr, 1, "users")
if err != nil {
b.FailNow()
}
type User struct {
ID int `kissorm:"id" db:"id"`
Name string `kissorm:"name" db:"name"`
Age int `kissorm:"age" db:"age"`
}
b.Run("kissorm-setup", func(b *testing.B) {
err := recreateTable(connStr)
if err != nil {
b.Fatalf("error creating table: %s", err.Error())
}
b.Run("insert-one", func(b *testing.B) {
for i := 0; i < b.N; i++ {
err := kissormDB.Insert(ctx, &User{
Name: strconv.Itoa(i),
Age: i,
})
if err != nil {
b.Fatalf("insert error: %s", err.Error())
}
}
})
})
sqlxDB, err := sqlx.Open(driver, connStr)
sqlxDB.SetMaxOpenConns(1)
b.Run("sqlx-setup", func(b *testing.B) {
err := recreateTable(connStr)
if err != nil {
b.Fatalf("error creating table: %s", err.Error())
}
query := `INSERT INTO users(name, age) VALUES (:name, :age) RETURNING id`
b.Run("insert-one", func(b *testing.B) {
for i := 0; i < b.N; i++ {
user := User{
Name: strconv.Itoa(i),
Age: i,
}
rows, err := sqlxDB.NamedQuery(query, user)
if err != nil {
b.Fatalf("insert error: %s", err.Error())
}
if !rows.Next() {
b.Fatalf("missing id from inserted record")
}
rows.Scan(&user.ID)
err = rows.Close()
if err != nil {
b.Fatalf("error closing rows")
}
}
})
})
}
func BenchmarkQuery(b *testing.B) {
ctx := context.Background()
driver := "postgres"
connStr := "host=localhost port=5432 user=postgres password=postgres dbname=kissorm sslmode=disable"
kissormDB, err := kissorm.New(driver, connStr, 1, "users")
if err != nil {
b.FailNow()
}
type User struct {
ID int `kissorm:"id" db:"id"`
Name string `kissorm:"name" db:"name"`
Age int `kissorm:"age" db:"age"`
}
b.Run("kissorm-setup", func(b *testing.B) {
err := recreateTable(connStr)
if err != nil {
b.Fatalf("error creating table: %s", err.Error())
}
err = insertUsers(connStr, 100)
if err != nil {
b.Fatalf("error inserting users: %s", err.Error())
}
b.Run("single-row", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var user User
err := kissormDB.QueryOne(ctx, &user, `SELECT * FROM users OFFSET $1 LIMIT 1`, i%100)
if err != nil {
b.Fatalf("query error: %s", err.Error())
}
}
})
b.Run("multiple-rows", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var users []User
err := kissormDB.Query(ctx, &users, `SELECT * FROM users OFFSET $1 LIMIT 10`, i%90)
if err != nil {
b.Fatalf("query error: %s", err.Error())
}
if len(users) < 10 {
b.Fatalf("expected 10 scanned users, but got: %d", len(users))
}
}
})
})
sqlxDB, err := sqlx.Open(driver, connStr)
sqlxDB.SetMaxOpenConns(1)
b.Run("sqlx-setup", func(b *testing.B) {
err := recreateTable(connStr)
if err != nil {
b.Fatalf("error creating table: %s", err.Error())
}
err = insertUsers(connStr, 100)
if err != nil {
b.Fatalf("error inserting users: %s", err.Error())
}
b.Run("single-row", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var user User
rows, err := sqlxDB.Queryx(`SELECT * FROM users OFFSET $1 LIMIT 1`, i%100)
if err != nil {
b.Fatalf("insert error: %s", err.Error())
}
if !rows.Next() {
b.Fatalf("missing user from inserted record, offset: %d", i%100)
}
rows.StructScan(&user)
err = rows.Close()
if err != nil {
b.Fatalf("error closing rows")
}
}
})
b.Run("multiple-rows", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var users []User
rows, err := sqlxDB.Queryx(`SELECT * FROM users OFFSET $1 LIMIT 10`, i%90)
if err != nil {
b.Fatalf("insert error: %s", err.Error())
}
for j := 0; j < 10; j++ {
if !rows.Next() {
b.Fatalf("missing user from inserted record, offset: %d", i%100)
}
var user User
rows.StructScan(&user)
users = append(users, user)
}
if len(users) < 10 {
b.Fatalf("expected 10 scanned users, but got: %d", len(users))
}
err = rows.Close()
if err != nil {
b.Fatalf("error closing rows")
}
}
})
})
}
func recreateTable(connStr string) error {
db, err := sql.Open("postgres", connStr)
if err != nil {
return err
}
defer db.Close()
db.Exec(`DROP TABLE users`)
_, err = db.Exec(`CREATE TABLE users (
id serial PRIMARY KEY,
age INT,
name VARCHAR(50)
)`)
if err != nil {
return fmt.Errorf("failed to create new users table: %s", err.Error())
}
return nil
}
func insertUsers(connStr string, numUsers int) error {
db, err := sql.Open("postgres", connStr)
if err != nil {
return err
}
defer db.Close()
for i := 0; i < numUsers; i++ {
_, err = db.Exec(`INSERT INTO users (name, age) VALUES ($1, $2)`, strconv.Itoa(i), i)
if err != nil {
return fmt.Errorf("failed to insert new user: %s", err.Error())
}
}
return nil
}

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.14
require (
github.com/ditointernet/go-assert v0.0.0-20200120164340-9e13125a7018
github.com/golang/mock v1.4.4
github.com/jmoiron/sqlx v1.2.0
github.com/lib/pq v1.1.1
github.com/mattn/go-sqlite3 v1.14.6
github.com/pkg/errors v0.9.1

5
go.sum
View File

@ -4,11 +4,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ditointernet/go-assert v0.0.0-20200120164340-9e13125a7018 h1:QsFkVafcKOaZoAB4WcyUHdkPbwh+VYwZgYJb/rU6EIM=
github.com/ditointernet/go-assert v0.0.0-20200120164340-9e13125a7018/go.mod h1:5C3SWkut69TSdkerzRDxXMRM5x73PGWNcRLe/xKjXhs=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@ -844,7 +844,6 @@ func TestTransaction(t *testing.T) {
_ = c.Insert(ctx, &u2)
err = c.Transaction(ctx, func(db ORMProvider) error {
fmt.Printf("received db client: %#v\n", db)
err = db.Insert(ctx, &User{Name: "User3"})
assert.Equal(t, nil, err)
err = db.Insert(ctx, &User{Name: "User4"})