sqlx和gorm性能对比

2022-12-03 00:56:46 浏览数 (1)

前言

gorm(stars: 29K)是基于go开发的一个ORM工具, sqlx (stars: 12.3K)是一个基于go语言开发的, 在原生go-sql-driver/mysql(stars: 12.4K)上拓展的库.

image.pngimage.png

他们是目前业界用的较多的3个组件, 故此对这几个组件进行一个简单的性能测试.

环境说明

代码语言:txt复制
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
版本: mysql  Ver 14.14 Distrib 5.7.20, for macos10.12 (x86_64) 
数据量: 2W, 目前仅测试select查询性能, 因为这块我们使用最频繁

表定义

代码语言:sql复制
CREATE TABLE `person` (
		`first_name` text,
		`last_name` text,
		`email` text,
		`id` int NOT NULL AUTO_INCREMENT,
		PRIMARY KEY (`id`)
	) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;

性能测试

代码语言:go复制
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"testing"
	"time"
)

type Person struct {
	Id        int    `db:"id"`
	FirstName string `db:"first_name"`
	LastName  string `db:"last_name"`
	Email     string `db:"email"`
}

func (p Person) TableName() string {
	return "person"
}

func Benchmark(b *testing.B) {
	dsn := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8&parseTime=True&loc=UTC",
		"root", "362427gg", "localhost", 3306, "test")

	limits := []int{
		5,
		50,
		500,
		10000,
	}
	// 原生mysql连接池
	sqlDB, _ := sql.Open("mysql", dsn)
	sqlDB.SetMaxOpenConns(500)
	sqlDB.SetMaxIdleConns(100)

	// sqlx连接池
	sqlxDB, _ := sqlx.Connect("mysql", dsn)
	sqlxDB.SetMaxOpenConns(500)
	sqlxDB.SetMaxIdleConns(100)

	// gorm
	gormDB, _ := 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)

	for _, lim := range limits {
		lim := lim

		// Benchmark origin
		b.Run(fmt.Sprintf("sql limit:%d", lim), func(b *testing.B) {
			for i := 0; i < b.N; i   {
				q := fmt.Sprintf("SELECT id,first_name,last_name,email FROM test.person ORDER BY id LIMIT %d", lim)
				var res []Person
				rows, err := sqlDB.Query(q)
				if err != nil {
					b.Fatal(err)
				}
				defer rows.Close()
				for rows.Next() {
					p := Person{}
					rows.Scan(&p.Id, &p.FirstName, &p.LastName, &p.Email)
					res = append(res, p)
				}
			}
		})

		// 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 id,first_name,last_name,email FROM test.person ORDER BY id LIMIT %d", lim)
				var res []Person
				err := sqlxDB.Select(&res, q)
				if err != nil {
					b.Fatal(err)
				}
			}
		})
		// Benchmark gormDB
		b.Run(fmt.Sprintf("gormDB limit:%d", lim), func(b *testing.B) {
			for i := 0; i < b.N; i   {
				var res []Person
				err := gormDB.Order("id").Limit(lim).Find(&res).Error
				if err != nil {
					b.Fatal(err)
				}
			}
		})

		fmt.Println("==================================================================================================================")
	}
}

测试结果

sql原生组件性能最高但是和sqlx相差10~20%, gorm的性能最差, 比原生差10~50%

代码语言:txt复制
$  GORM_DIALECT=mysql go test -bench=. -benchmem
goos: darwin
goarch: amd64
pkg: grpc-demo
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Benchmark/sql_limit:5-12                    9044            122952 ns/op            2602 B/op         63 allocs/op
Benchmark/sqlx_limit:5-12                   9093            124345 ns/op            2889 B/op         70 allocs/op
Benchmark/gormDB_limit:5-12                 8854            132475 ns/op            5646 B/op        106 allocs/op
==================================================================================================================
Benchmark/sql_limit:50-12                   5750            202876 ns/op           17971 B/op        467 allocs/op
Benchmark/sqlx_limit:50-12                  5120            219263 ns/op           19340 B/op        519 allocs/op
Benchmark/gormDB_limit:50-12                4244            262799 ns/op           21851 B/op        689 allocs/op
==================================================================================================================
Benchmark/sql_limit:500-12                  1130           1037233 ns/op          161823 B/op       4521 allocs/op
Benchmark/sqlx_limit:500-12                  964           1207199 ns/op          167845 B/op       5023 allocs/op
Benchmark/gormDB_limit:500-12                741           1569280 ns/op          187316 B/op       6543 allocs/op
==================================================================================================================
Benchmark/sql_limit:10000-12                 100          11728373 ns/op         4648238 B/op      90034 allocs/op
Benchmark/sqlx_limit:10000-12                100          12551046 ns/op         4882252 B/op     100037 allocs/op
Benchmark/gormDB_limit:10000-12               60          19835525 ns/op         5031278 B/op     130076 allocs/op
==================================================================================================================
PASS
ok      grpc-demo       14.946s

分析原因

sqlx为啥比gorm快?

(1) interface{}问题

GORM中许多函数入参的数据类型都是interface{},底层又用reflect支持了多种类型,这种实现会导致两个问题:

  • reflect导致的底层的性能不高(这点还能接受)
  • interface{}如果传入了不支持的复杂数据类型时,排查问题麻烦,往往要运行程序时才会报错

而在sqlx中测试使用的是原生的sql, 基本没有额外的反射操作.

(2) 高频拼接重复SQL

在一个程序运行过程中,执行的SQL语句都比较固定,而变化的往往是参数, 从GORM的实现来看,每次执行都需要重新拼接一次SQL语句,性能肯定也是有影响的.

而在sqlx中测试使用的是原生的sql, 只是做了个简单的字符串format操作

0 人点赞