Added plan of tests
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
package benchmarks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
sqlc "github.com/rexfordnyrk/go-db-comparison/benchmarks/sqlc_generated"
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
// Opening a database connection.
|
||||
db, err = sql.Open("mysql", "theuser:thepass@tcp(localhost:3306)/thedb?multiStatements=true&parseTime=true")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//sqlx connection using existing db connection
|
||||
dbx = sqlx.NewDb(db, "mysql")
|
||||
|
||||
//sqlc connection using existing db connection
|
||||
dbc = sqlc.New(db)
|
||||
|
||||
//gorm connection using existing db connection
|
||||
gdb, err = gorm.Open(mysql.New(mysql.Config{Conn: db}))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
gdb *gorm.DB
|
||||
db *sql.DB
|
||||
dbx *sqlx.DB
|
||||
dbc *sqlc.Queries
|
||||
)
|
||||
|
||||
func setup() {
|
||||
clear()
|
||||
table := `CREATE TABLE students (
|
||||
id bigint NOT NULL AUTO_INCREMENT,
|
||||
fname varchar(50) not null,
|
||||
lname varchar(50) not null,
|
||||
date_of_birth datetime not null,
|
||||
email varchar(50) not null,
|
||||
address varchar(50) not null,
|
||||
gender varchar(50) not null,
|
||||
PRIMARY KEY (id)
|
||||
);`
|
||||
_, err := db.Exec(table)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//inserting records
|
||||
_, err = db.Exec(records)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func clear() {
|
||||
_, err := db.Exec(`DROP TABLE IF EXISTS students;`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
type Student struct {
|
||||
ID int64
|
||||
Fname string
|
||||
Lname string
|
||||
DateOfBirth time.Time `db:"date_of_birth"`
|
||||
Email string
|
||||
Address string
|
||||
Gender string
|
||||
}
|
||||
|
||||
func DbSqlQueryStudentWithLimit(limit int) {
|
||||
var students []Student
|
||||
rows, err := db.Query("SELECT * FROM students limit ?", limit)
|
||||
if err != nil {
|
||||
log.Fatalf("DbSqlQueryStudentWithLimit %d %v", limit, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Loop through rows, using Scan to assign column data to struct fields.
|
||||
for rows.Next() {
|
||||
var s Student
|
||||
if err := rows.Scan(&s.ID, &s.Fname, &s.Lname, &s.DateOfBirth, &s.Email, &s.Address, &s.Gender); err != nil {
|
||||
log.Fatalf("DbSqlQueryStudentWithLimit %d %v", limit, err)
|
||||
}
|
||||
students = append(students, s)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Fatalf("DbSqlQueryStudentWithLimit %d %v", limit, err)
|
||||
}
|
||||
}
|
||||
|
||||
func SqlxQueryStudentWithLimit(limit int) {
|
||||
var students []Student
|
||||
err := dbx.Select(&students, "SELECT * FROM students LIMIT ?", limit)
|
||||
if err != nil {
|
||||
log.Fatalf("SqlxQueryStudentWithLimit %d %v", limit, err)
|
||||
}
|
||||
}
|
||||
|
||||
func SqlcQueryStudentWithLimit(limit int) {
|
||||
_, err := dbc.FetchStudents(context.Background(), int32(limit))
|
||||
if err != nil {
|
||||
log.Fatalf("SqlcQueryStudentWithLimit %d %v", limit, err)
|
||||
}
|
||||
}
|
||||
|
||||
func GormQueryStudentWithLimit(limit int) {
|
||||
var students []Student
|
||||
if err := gdb.Limit(limit).Find(&students).Error; err != nil {
|
||||
log.Fatalf("GormQueryStudentWithLimit %d %v", limit, err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package benchmarks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Benchmark(b *testing.B) {
|
||||
setup()
|
||||
defer clear()
|
||||
|
||||
// Benchmark goes in here
|
||||
limits := []int{
|
||||
1,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
15000,
|
||||
}
|
||||
|
||||
for _, lim := range limits { // Fetch varying number of rows
|
||||
|
||||
fmt.Printf("================================== BENCHMARKING %d RECORDS ======================================\n", lim)
|
||||
// Benchmark Database/sql
|
||||
b.Run(fmt.Sprintf("Database/sql limit:%d ", lim), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
DbSqlQueryStudentWithLimit(lim)
|
||||
}
|
||||
})
|
||||
|
||||
// Benchmark Sqlx
|
||||
b.Run(fmt.Sprintf("Sqlx limit:%d ", lim), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
SqlxQueryStudentWithLimit(lim)
|
||||
}
|
||||
})
|
||||
|
||||
// Benchmark Sqlc
|
||||
b.Run(fmt.Sprintf("Sqlc limit:%d ", lim), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
SqlcQueryStudentWithLimit(lim)
|
||||
}
|
||||
})
|
||||
|
||||
// Benchmark GORM
|
||||
b.Run(fmt.Sprintf("GORM limit:%d ", lim), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
GormQueryStudentWithLimit(lim)
|
||||
}
|
||||
})
|
||||
|
||||
fmt.Println("=================================================================================================")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.16.0
|
||||
|
||||
package sqlc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type DBTX interface {
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
PrepareContext(context.Context, string) (*sql.Stmt, error)
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
func New(db DBTX) *Queries {
|
||||
return &Queries{db: db}
|
||||
}
|
||||
|
||||
type Queries struct {
|
||||
db DBTX
|
||||
}
|
||||
|
||||
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
||||
return &Queries{
|
||||
db: tx,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.16.0
|
||||
|
||||
package sqlc
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Student struct {
|
||||
ID int64
|
||||
Fname string
|
||||
Lname string
|
||||
DateOfBirth time.Time
|
||||
Email string
|
||||
Address string
|
||||
Gender string
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
-- name: FetchStudents :many
|
||||
SELECT * FROM students LIMIT ?;
|
||||
@@ -0,0 +1,45 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.16.0
|
||||
// source: query.sql
|
||||
|
||||
package sqlc
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const fetchStudents = `-- name: FetchStudents :many
|
||||
SELECT id, fname, lname, date_of_birth, email, address, gender FROM students LIMIT ?
|
||||
`
|
||||
|
||||
func (q *Queries) FetchStudents(ctx context.Context, limit int32) ([]Student, error) {
|
||||
rows, err := q.db.QueryContext(ctx, fetchStudents, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Student
|
||||
for rows.Next() {
|
||||
var i Student
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Fname,
|
||||
&i.Lname,
|
||||
&i.DateOfBirth,
|
||||
&i.Email,
|
||||
&i.Address,
|
||||
&i.Gender,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `students` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`fname` varchar(50) not null,
|
||||
`lname` varchar(50) not null,
|
||||
`date_of_birth` datetime not null,
|
||||
`email` varchar(50) not null,
|
||||
`address` varchar(50) not null,
|
||||
`gender` varchar(50) not null,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
@@ -0,0 +1,7 @@
|
||||
version: 1
|
||||
packages:
|
||||
- path: "./"
|
||||
name: "sqlc"
|
||||
engine: "mysql"
|
||||
schema: "schema.sql"
|
||||
queries: "query.sql"
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user