mirror of https://github.com/go-gorm/gorm.git
enhancement: Avoid calling reflect.New() when passing in slice of values to `Scan()` (#5388)
* fix: reduce allocations when slice of values * chore[test]: Add benchmark for scan * chore[test]: add bench for scan slice * chore[test]: add bench for slice pointer and improve tests * chore[test]: make sure database is empty when doing slice tests * fix[test]: correct sql delete statement * enhancement: skip new if rows affected = 0
This commit is contained in:
parent
f4e9904b02
commit
d01de7232b
7
scan.go
7
scan.go
|
@ -237,6 +237,7 @@ func Scan(rows Rows, db *DB, mode ScanMode) {
|
|||
switch reflectValue.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
var elem reflect.Value
|
||||
recyclableStruct := reflect.New(reflectValueType)
|
||||
|
||||
if !update || reflectValue.Len() == 0 {
|
||||
update = false
|
||||
|
@ -261,7 +262,11 @@ func Scan(rows Rows, db *DB, mode ScanMode) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
elem = reflect.New(reflectValueType)
|
||||
if isPtr && db.RowsAffected > 0 {
|
||||
elem = reflect.New(reflectValueType)
|
||||
} else {
|
||||
elem = recyclableStruct
|
||||
}
|
||||
}
|
||||
|
||||
db.scanIntoStruct(rows, elem, values, fields, joinFields)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package tests_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
. "gorm.io/gorm/utils/tests"
|
||||
|
@ -24,6 +25,45 @@ func BenchmarkFind(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkScan(b *testing.B) {
|
||||
user := *GetUser("scan", Config{})
|
||||
DB.Create(&user)
|
||||
|
||||
var u User
|
||||
b.ResetTimer()
|
||||
for x := 0; x < b.N; x++ {
|
||||
DB.Raw("select * from users where id = ?", user.ID).Scan(&u)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScanSlice(b *testing.B) {
|
||||
DB.Exec("delete from users")
|
||||
for i := 0; i < 10_000; i++ {
|
||||
user := *GetUser(fmt.Sprintf("scan-%d", i), Config{})
|
||||
DB.Create(&user)
|
||||
}
|
||||
|
||||
var u []User
|
||||
b.ResetTimer()
|
||||
for x := 0; x < b.N; x++ {
|
||||
DB.Raw("select * from users").Scan(&u)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScanSlicePointer(b *testing.B) {
|
||||
DB.Exec("delete from users")
|
||||
for i := 0; i < 10_000; i++ {
|
||||
user := *GetUser(fmt.Sprintf("scan-%d", i), Config{})
|
||||
DB.Create(&user)
|
||||
}
|
||||
|
||||
var u []*User
|
||||
b.ResetTimer()
|
||||
for x := 0; x < b.N; x++ {
|
||||
DB.Raw("select * from users").Scan(&u)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUpdate(b *testing.B) {
|
||||
user := *GetUser("find", Config{})
|
||||
DB.Create(&user)
|
||||
|
|
Loading…
Reference in New Issue