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
					
				
							
								
								
									
										5
									
								
								scan.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								scan.go
									
									
									
									
									
								
							| @ -237,6 +237,7 @@ func Scan(rows Rows, db *DB, mode ScanMode) { | |||||||
| 		switch reflectValue.Kind() { | 		switch reflectValue.Kind() { | ||||||
| 		case reflect.Slice, reflect.Array: | 		case reflect.Slice, reflect.Array: | ||||||
| 			var elem reflect.Value | 			var elem reflect.Value | ||||||
|  | 			recyclableStruct := reflect.New(reflectValueType) | ||||||
| 
 | 
 | ||||||
| 			if !update || reflectValue.Len() == 0 { | 			if !update || reflectValue.Len() == 0 { | ||||||
| 				update = false | 				update = false | ||||||
| @ -261,7 +262,11 @@ func Scan(rows Rows, db *DB, mode ScanMode) { | |||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} else { | 				} else { | ||||||
|  | 					if isPtr && db.RowsAffected > 0 { | ||||||
| 						elem = reflect.New(reflectValueType) | 						elem = reflect.New(reflectValueType) | ||||||
|  | 					} else { | ||||||
|  | 						elem = recyclableStruct | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				db.scanIntoStruct(rows, elem, values, fields, joinFields) | 				db.scanIntoStruct(rows, elem, values, fields, joinFields) | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package tests_test | package tests_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	. "gorm.io/gorm/utils/tests" | 	. "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) { | func BenchmarkUpdate(b *testing.B) { | ||||||
| 	user := *GetUser("find", Config{}) | 	user := *GetUser("find", Config{}) | ||||||
| 	DB.Create(&user) | 	DB.Create(&user) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Bexanderthebex
						Bexanderthebex