mirror of https://github.com/VinGarcia/ksql.git
Add a Benchmark comparing us with the sqlx package
parent
f655576bb3
commit
e1e711dc91
5
Makefile
5
Makefile
|
@ -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)
|
||||
|
|
22
README.md
22
README.md
|
@ -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
|
||||
|
|
|
@ -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
1
go.mod
|
@ -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
5
go.sum
|
@ -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=
|
||||
|
|
|
@ -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"})
|
||||
|
|
Loading…
Reference in New Issue