Improve preload speed (#2058)

All credits to @vanjapt who came up with this patch.

Closes #1672
This commit is contained in:
maddie 2018-09-10 06:45:55 +08:00 committed by Jinzhu
parent 73e7561e20
commit 012d147974
1 changed files with 22 additions and 11 deletions

View File

@ -161,14 +161,17 @@ func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{})
) )
if indirectScopeValue.Kind() == reflect.Slice { if indirectScopeValue.Kind() == reflect.Slice {
foreignValuesToResults := make(map[string]reflect.Value)
for i := 0; i < resultsValue.Len(); i++ {
result := resultsValue.Index(i)
foreignValues := toString(getValueFromFields(result, relation.ForeignFieldNames))
foreignValuesToResults[foreignValues] = result
}
for j := 0; j < indirectScopeValue.Len(); j++ { for j := 0; j < indirectScopeValue.Len(); j++ {
for i := 0; i < resultsValue.Len(); i++ { indirectValue := indirect(indirectScopeValue.Index(j))
result := resultsValue.Index(i) valueString := toString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames))
foreignValues := getValueFromFields(result, relation.ForeignFieldNames) if result, found := foreignValuesToResults[valueString]; found {
if indirectValue := indirect(indirectScopeValue.Index(j)); equalAsString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames), foreignValues) { indirectValue.FieldByName(field.Name).Set(result)
indirectValue.FieldByName(field.Name).Set(result)
break
}
} }
} }
} else { } else {
@ -255,13 +258,21 @@ func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{
indirectScopeValue = scope.IndirectValue() indirectScopeValue = scope.IndirectValue()
) )
foreignFieldToObjects := make(map[string][]*reflect.Value)
if indirectScopeValue.Kind() == reflect.Slice {
for j := 0; j < indirectScopeValue.Len(); j++ {
object := indirect(indirectScopeValue.Index(j))
valueString := toString(getValueFromFields(object, relation.ForeignFieldNames))
foreignFieldToObjects[valueString] = append(foreignFieldToObjects[valueString], &object)
}
}
for i := 0; i < resultsValue.Len(); i++ { for i := 0; i < resultsValue.Len(); i++ {
result := resultsValue.Index(i) result := resultsValue.Index(i)
if indirectScopeValue.Kind() == reflect.Slice { if indirectScopeValue.Kind() == reflect.Slice {
value := getValueFromFields(result, relation.AssociationForeignFieldNames) valueString := toString(getValueFromFields(result, relation.AssociationForeignFieldNames))
for j := 0; j < indirectScopeValue.Len(); j++ { if objects, found := foreignFieldToObjects[valueString]; found {
object := indirect(indirectScopeValue.Index(j)) for _, object := range objects {
if equalAsString(getValueFromFields(object, relation.ForeignFieldNames), value) {
object.FieldByName(field.Name).Set(result) object.FieldByName(field.Name).Set(result)
} }
} }