170W数据下,sqlx和gorm查询不同条数数据性能对比,机器配置 8核/16G,mysql分别最大连接数为1 和 最大连接数500最大空闲连接数100的情况下测试。
package tesst
import (
"fmt"
"testing"
"time"
"github.com/jmoiron/sqlx"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type ShardingDB struct {
ID uint64 `db:"id" gorm:"column:id"`
DBID string `db:"db_id" gorm:"column:db_id"`
Host string `db:"host" gorm:"column:host"`
Port int32 `db:"port" gorm:"column:port"`
User string `db:"user" gorm:"column:user"`
Password string `db:"password" gorm:"column:password"`
Memo string `db:"memo" gorm:"column:memo"`
State int32 `db:"state" gorm:"column:state"`
CreatedAt time.Time `db:"create_time" gorm:"column:create_time"`
UpdatedAt time.Time `db:"update_time" gorm:"column:update_time"`
}
// TableName returns table name of sharding_db.
func (s *ShardingDB) TableName() string {
return "sharding_db"
}
var (
dbhostsip = "127.0.0.1" // IP地址
dbport = 3306 // Port
dbusername = "root" // 用户名
dbpassword = "admin" // 密码
dbname = "test" // 表名
)
func Benchmark(b *testing.B) {
dsn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8&parseTime=True&loc=UTC",
dbusername, dbpassword, dbhostsip, dbport, dbname)
limits := []int{
5,
50,
500,
10000,
}
sqlxDB, _ := sqlx.Connect("mysql", dsn)
sqlxDB.SetMaxOpenConns(500)
sqlxDB.SetMaxIdleConns(100)
gormDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{NowFunc: func() time.Time { return time.Now().UTC().Round(time.Microsecond) }})
db, _ := gormDB.DB()
db.SetMaxOpenConns(500)
db.SetMaxIdleConns(100)
fmt.Println("=============================== CPU:8 MEM:16G MaxOpenConns:500 MaxOpenConns:100 ====================================")
for _, lim := range limits {
lim := lim
// Benchmark sqlx
b.Run(fmt.Sprintf("sqlx limit:%d", lim), func(b *testing.B) {
for i := 0; i < b.N; i++ {
q := fmt.Sprintf("SELECT * FROM sharding_db ORDER BY id LIMIT %d", lim)
res := []ShardingDB{}
err := sqlxDB.Select(&res, q)
if err != nil {
b.Fatal(err)
}
}
})
if err != nil {
panic(err)
}
// Benchmark gormDB
b.Run(fmt.Sprintf("gormDB limit:%d", lim), func(b *testing.B) {
for i := 0; i < b.N; i++ {
for i := 0; i < b.N; i++ {
var res = []ShardingDB{}
err := gormDB.Order("id").Limit(lim).Find(&res).Error
if err != nil {
b.Fatal(err)
}
}
}
})
fmt.Println("==================================================================================================================")
}
}
=============================== CPU:8 MEM:16G MaxOpenConns:1 ====================================
goos: linux
goarch: amd64
pkg: go-operation-demo/sqlx/bench-test-demo
Benchmark/sqlx_limit:5-8 10000 102170 ns/op 7275 B/op 134 allocs/op
Benchmark/gormDB_limit:5-8 100 13250163 ns/op 1199221 B/op 29300 allocs/op
==================================================================================================================
Benchmark/sqlx_limit:50-8 4472 270684 ns/op 52652 B/op 1082 allocs/op
Benchmark/gormDB_limit:50-8 100 52683096 ns/op 7362504 B/op 250000 allocs/op
==================================================================================================================
Benchmark/sqlx_limit:500-8 814 1480242 ns/op 480048 B/op 10536 allocs/op
Benchmark/gormDB_limit:500-8 100 395335077 ns/op 68082795 B/op 2455402 allocs/op
==================================================================================================================
Benchmark/sqlx_limit:10000-8 39 28053826 ns/op 14964052 B/op 210053 allocs/op
Benchmark/gormDB_limit:10000-8 14 1086946301 ns/op 254799549 B/op 6860912 allocs/op
==================================================================================================================
PASS
ok go-operation-demo/sqlx/bench-test-demo 66.189s
=============================== CPU:8 MEM:16G MaxOpenConns:500 MaxIdleConns:100 ====================================
goos: linux
goarch: amd64
pkg: go-operation-demo/sqlx/bench-test-demo
Benchmark/sqlx_limit:5-8 10000 100589 ns/op 7274 B/op 134 allocs/op
Benchmark/gormDB_limit:5-8 100 13322948 ns/op 1199224 B/op 29300 allocs/op
==================================================================================================================
Benchmark/sqlx_limit:50-8 4651 265969 ns/op 52652 B/op 1082 allocs/op
Benchmark/gormDB_limit:50-8 100 52195341 ns/op 7362505 B/op 250000 allocs/op
==================================================================================================================
Benchmark/sqlx_limit:500-8 820 1466335 ns/op 480048 B/op 10536 allocs/op
Benchmark/gormDB_limit:500-8 100 395699610 ns/op 68082802 B/op 2455402 allocs/op
==================================================================================================================
Benchmark/sqlx_limit:10000-8 40 28599357 ns/op 14964058 B/op 210053 allocs/op
Benchmark/gormDB_limit:10000-8 15 1158298778 ns/op 272999555 B/op 7350977 allocs/op
==================================================================================================================
PASS
ok go-operation-demo/sqlx/bench-test-demo 68.395s
Sqlx 查询时间和内存占用远远小于 Gorm。
对于系统db层面来说,每个model都需要CRUD操作,如果不对Sqlx再封装一层的话,使用起来需要写大量的Sqlx的冗余代码。但是如果封装一层的话,就需要考虑性能消耗和临时变量的消耗,这里仅举一个Select的示例。
package database
import (
"fmt"
"log"
"testing"
"time"
"github.com/jmoiron/sqlx"
_ "gorm.io/driver/mysql"
)
type ShardingDB struct {
ID uint64 `db:"id" gorm:"column:id"`
DBID string `db:"db_id" gorm:"column:db_id"`
Host string `db:"host" gorm:"column:host"`
Port int32 `db:"port" gorm:"column:port"`
User string `db:"user" gorm:"column:user"`
Password string `db:"password" gorm:"column:password"`
Memo string `db:"memo" gorm:"column:memo"`
State int32 `db:"state" gorm:"column:state"`
CreatedAt time.Time `db:"create_time" gorm:"column:create_time"`
UpdatedAt time.Time `db:"update_time" gorm:"column:update_time"`
}
// TableName returns table name of sharding_db.
func (s *ShardingDB) TableName() string {
return "sharding_db"
}
var (
dbhostsip = "127.0.0.1" // IP地址
dbport = 3306 // Port
dbusername = "root" // 用户名
dbpassword = "admin" // 密码
dbname = "test" // 表名
)
func Benchmark(b *testing.B) {
dsn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8&parseTime=True&loc=UTC",
dbusername, dbpassword, dbhostsip, dbport, dbname)
limits := []int{
5,
50,
500,
10000,
}
fmt.Println("=============================== CPU:8 MEM:16G MaxOpenConns:500 MaxIdleConns:100 ====================================")
for _, lim := range limits {
lim := lim
// Benchmark sqlx
b.Run(fmt.Sprintf("sqlx query limit:%d", lim), func(b *testing.B) {
sqlxDB, err := sqlx.Connect("mysql", dsn)
if err != nil {
log.Fatal(err)
}
sqlxDB.SetMaxOpenConns(1)
for i := 0; i < b.N; i++ {
sqlxQuery(sqlxDB, lim)
}
})
// 指针使用方式不可行,没办法映射字段
// b.Run(fmt.Sprintf("sqlx ptr query limit:%d", lim), func(b *testing.B) {
// sqlxDB, err := sqlx.Connect("mysql", dsn)
// if err != nil {
// log.Fatal(err)
// }
// sqlxDB.SetMaxOpenConns(1)
//
// for i := 0; i < b.N; i++ {
// sqlxPtrQuery(sqlxDB, lim)
// }
// })
b.Run(fmt.Sprintf("sqlx select query limit:%d", lim), func(b *testing.B) {
sqlxDB, err := sqlx.Connect("mysql", dsn)
if err != nil {
log.Fatal(err)
}
sqlxDB.SetMaxOpenConns(1)
for i := 0; i < b.N; i++ {
sqlxSelectQuery(sqlxDB, lim)
}
})
// 指针使用方式不可行,没办法映射字段
// b.Run(fmt.Sprintf("sqlx select ptr query limit:%d", lim), func(b *testing.B) {
// sqlxDB, err := sqlx.Connect("mysql", dsn)
// if err != nil {
// log.Fatal(err)
// }
// sqlxDB.SetMaxOpenConns(1)
//
// for i := 0; i < b.N; i++ {
// sqlxSelectPtrQuery(sqlxDB, lim)
// }
// })
fmt.Println("==================================================================================================================")
}
}
func sqlxQuery(sqlxDB *sqlx.DB, lim int) (shardingDB []ShardingDB) {
q := fmt.Sprintf("SELECT * FROM sharding_db ORDER BY id LIMIT %d", lim)
err := sqlxDB.Select(&shardingDB, q)
if err != nil {
log.Fatal(err)
}
return
}
func sqlxPtrQuery(sqlxDB *sqlx.DB, lim int) (shardingDB *[]ShardingDB) {
q := fmt.Sprintf("SELECT * FROM sharding_db ORDER BY id LIMIT %d", lim)
err := sqlxDB.Select(shardingDB, q)
if err != nil {
log.Fatal(err)
}
return
}
func sqlxSelectQuery(sqlxDB *sqlx.DB, lim int) (shardingDB []ShardingDB) {
q := fmt.Sprintf("SELECT * FROM sharding_db ORDER BY id LIMIT %d", lim)
err := SqlxSelect(sqlxDB, &shardingDB, q)
if err != nil {
log.Fatal(err)
}
return
}
func sqlxSelectPtrQuery(sqlxDB *sqlx.DB, lim int) (shardingDB *[]ShardingDB) {
q := fmt.Sprintf("SELECT * FROM sharding_db ORDER BY id LIMIT %d", lim)
err := SqlxSelect(sqlxDB, shardingDB, q)
if err != nil {
log.Fatal(err)
}
return
}
package database
import "github.com/jmoiron/sqlx"
var (
SqlxSelect = sqlxSelectFunc
)
// ================== raw execute func ==================
func sqlxSelectFunc(db *sqlx.DB, dest interface{}, query string, args ...interface{}) error {
query, args, err := sqlx.In(query, args...)
if err != nil {
return err
}
err = db.Select(dest, query, args...)
return err
}
=============================== CPU:8 MEM:16G MaxOpenConns:500 MaxIdleConns:100 ====================================
goos: linux
goarch: amd64
pkg: go-operation-demo/sqlx/bench-test-demo/pkg-comp
Benchmark/sqlx_query_limit:5-8 12006 99514 ns/op 7276 B/op 134 allocs/op
Benchmark/sqlx_select_query_limit:5-8 10000 101496 ns/op 7276 B/op 134 allocs/op
==================================================================================================================
Benchmark/sqlx_query_limit:50-8 4536 263568 ns/op 52654 B/op 1082 allocs/op
Benchmark/sqlx_select_query_limit:50-8 4440 264001 ns/op 52655 B/op 1082 allocs/op
==================================================================================================================
Benchmark/sqlx_query_limit:500-8 835 1447305 ns/op 480066 B/op 10536 allocs/op
Benchmark/sqlx_select_query_limit:500-8 826 1446552 ns/op 480066 B/op 10536 allocs/op
==================================================================================================================
Benchmark/sqlx_query_limit:10000-8 40 26950958 ns/op 14964317 B/op 210055 allocs/op
Benchmark/sqlx_select_query_limit:10000-8 40 26891873 ns/op 14964402 B/op 210054 allocs/op
==================================================================================================================
PASS
ok go-operation-demo/sqlx/bench-test-demo/pkg-comp 10.580s