diff --git a/README.md b/README.md index 8792b66..14120fc 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ All package run in no-cache mode. - [zorm](https://gitee.com/chunanyong/zorm) - [gen](https://gorm.io/gen/index.html) - [jet](https://github.com/go-jet/jet) +- [sq](https://github.com/bokwoon95/sq) See [`go.mod`](go.mod) for their latest versions. diff --git a/bench/sq.go b/bench/sq.go new file mode 100644 index 0000000..0ce45c9 --- /dev/null +++ b/bench/sq.go @@ -0,0 +1,177 @@ +package bench + +import ( + "database/sql" + "testing" + + qm "github.com/bokwoon95/sq" + "github.com/efectn/go-orm-benchmarks/bench/sq/db" + "github.com/efectn/go-orm-benchmarks/helper" +) + +// sq supports both templated queries and a query builder. +// This benchmark only uses the query builder. +type Sq struct { + helper.ORMInterface + conn *sql.DB +} + +func CreateSq() helper.ORMInterface { + return &Sq{} +} + +func (sq *Sq) Name() string { + return "sq" +} + +func (sq *Sq) Init() error { + var err error + sq.conn, err = sql.Open("pgx", helper.OrmSource) + if err != nil { + sq.conn = nil + return err + } + return nil +} + +func (sq *Sq) Close() error { + return sq.conn.Close() +} + +func (sq *Sq) Insert(b *testing.B) { + m := NewModelAlt() + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + m.Id = 0 + err := sq.insertModel(&m) + if err != nil { + helper.SetError(b, sq.Name(), "Insert", err.Error()) + } + } +} + +func (sq *Sq) InsertMulti(b *testing.B) { + ms := make([]Model, 0, 100) + for i := 0; i < 100; i++ { + ms = append(ms, NewModelAlt()) + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tbl := qm.New[db.MODELS]("") + query := qm.Postgres.InsertInto(tbl).Columns(tbl.NAME, tbl.TITLE, tbl.FAX, tbl.WEB, tbl.AGE, tbl.RIGHT, tbl.COUNTER) + for _, m := range ms { + query = query.Values(m.Name, m.Title, m.Fax, m.Web, m.Age, m.Right, m.Counter) + } + _, err := qm.Exec(sq.conn, query) + if err != nil { + helper.SetError(b, sq.Name(), "InsertMulti", err.Error()) + } + } +} + +func (sq *Sq) Update(b *testing.B) { + m := NewModelAlt() + + err := sq.insertModel(&m) + if err != nil { + helper.SetError(b, sq.Name(), "Update", err.Error()) + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tbl := qm.New[db.MODELS]("") + query := qm.Postgres.Update(tbl).Set( + tbl.NAME.SetString(m.Name), + tbl.TITLE.SetString(m.Title), + tbl.FAX.SetString(m.Fax), + tbl.WEB.SetString(m.Web), + tbl.AGE.SetInt(m.Age), + tbl.RIGHT.SetBool(m.Right), + tbl.COUNTER.SetInt64(m.Counter), + ).Where(tbl.ID.EqInt(m.Id)) + _, err = qm.Exec(sq.conn, query) + if err != nil { + helper.SetError(b, sq.Name(), "Update", err.Error()) + } + } +} + +func (sq *Sq) Read(b *testing.B) { + m := NewModelAlt() + + err := sq.insertModel(&m) + if err != nil { + helper.SetError(b, sq.Name(), "Read", err.Error()) + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tbl := qm.New[db.MODELS]("") + query := qm.Postgres.From(tbl).Where(tbl.ID.EqInt(m.Id)) + _, err = qm.FetchOne(sq.conn, query, sq.modelRowMapper(tbl)) + if err != nil { + helper.SetError(b, sq.Name(), "Read", err.Error()) + } + } +} + +func (sq *Sq) ReadSlice(b *testing.B) { + m := NewModelAlt() + + for i := 0; i < 100; i++ { + m.Id = 0 + err := sq.insertModel(&m) + if err != nil { + helper.SetError(b, sq.Name(), "ReadSlice", err.Error()) + } + } + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + tbl := qm.New[db.MODELS]("") + query := qm.Postgres.From(tbl).Where(tbl.ID.GtInt(0)).Limit(100) + _, err := qm.FetchAll(sq.conn, query, sq.modelRowMapper(tbl)) + if err != nil { + helper.SetError(b, sq.Name(), "ReadSlice", err.Error()) + } + } +} + +func (sq *Sq) insertModel(m *Model) error { + var err error + tbl := qm.New[db.MODELS]("") + query := qm.Postgres.InsertInto(tbl). + Columns(tbl.NAME, tbl.TITLE, tbl.FAX, tbl.WEB, tbl.AGE, tbl.RIGHT, tbl.COUNTER). + Values(m.Name, m.Title, m.Fax, m.Web, m.Age, m.Right, m.Counter) + m.Id, err = qm.FetchOne(sq.conn, query, func(r *qm.Row) int { + return r.IntField(tbl.ID) + }) + return err +} + +func (sq *Sq) modelRowMapper(tbl db.MODELS) func(*qm.Row) Model { + return func(r *qm.Row) Model { + return Model{ + Id: r.IntField(tbl.ID), + Name: r.StringField(tbl.NAME), + Title: r.StringField(tbl.TITLE), + Fax: r.StringField(tbl.FAX), + Web: r.StringField(tbl.WEB), + Age: r.IntField(tbl.AGE), + Right: r.BoolField(tbl.RIGHT), + Counter: r.Int64Field(tbl.COUNTER), + } + } +} diff --git a/bench/sq/db/models.go b/bench/sq/db/models.go new file mode 100644 index 0000000..d5f5902 --- /dev/null +++ b/bench/sq/db/models.go @@ -0,0 +1,17 @@ +package db + +import ( + "github.com/bokwoon95/sq" +) + +type MODELS struct { + sq.TableStruct + ID sq.NumberField + NAME sq.StringField + TITLE sq.StringField + FAX sq.StringField + WEB sq.StringField + AGE sq.NumberField + RIGHT sq.BooleanField + COUNTER sq.NumberField +} diff --git a/go.mod b/go.mod index 5f67c13..6d7a61b 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( entgo.io/ent v0.12.3 gitee.com/chunanyong/zorm v1.6.9 github.com/astaxie/beego v1.12.3 + github.com/bokwoon95/sq v0.5.0 github.com/friendsofgo/errors v0.9.2 github.com/go-jet/jet/v2 v2.10.1 github.com/go-pg/pg/v10 v10.11.1 diff --git a/go.sum b/go.sum index 2b937c8..186c8d4 100644 --- a/go.sum +++ b/go.sum @@ -122,6 +122,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bokwoon95/sq v0.5.0 h1:h8wckz1u2fxJazszPbYDjW8cx9K65nv4xvLT7QdwA3o= +github.com/bokwoon95/sq v0.5.0/go.mod h1:E3X8ARaXQ77XGMvjS0sQrcA1F5BZvq4Ck/91dPsMKR4= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8= github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc= diff --git a/main.go b/main.go index 65ec450..e5ace00 100644 --- a/main.go +++ b/main.go @@ -27,7 +27,7 @@ var defaultBenchmarkNames = []string{ "pg", "pgx", "pgx_pool", "pop", "raw", "reform", "rel", "sqlboiler", "sqlc", "sqlx", "upper", "xorm", - "zorm", "gen", "jet", + "zorm", "gen", "jet", "sq", } type ListOpts []string @@ -125,6 +125,7 @@ func runBenchmarks(orms ListOpts) { "zorm": bench.CreateZorm(), "gen": bench.CreateGen(), "jet": bench.CreateJet(), + "sq": bench.CreateSq(), } table := new(tabwriter.Writer)