diff --git a/scan.go b/scan.go index a611a9ce8..1bb51560a 100644 --- a/scan.go +++ b/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) diff --git a/tests/benchmark_test.go b/tests/benchmark_test.go index d897a6341..22d15898e 100644 --- a/tests/benchmark_test.go +++ b/tests/benchmark_test.go @@ -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)