Skip to content

Commit

Permalink
Split preloading-IN query into multiple queries (go-rel#283)
Browse files Browse the repository at this point in the history
  • Loading branch information
aligator committed May 24, 2022
1 parent c315e44 commit e3cd023
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
1 change: 1 addition & 0 deletions cursor.go
Expand Up @@ -81,6 +81,7 @@ func scanMulti(cur Cursor, keyField string, keyType reflect.Type, cols map[inter
}

if !found && fields != nil {
// TODO: why a panic and not just an easily catchable error?
panic("rel: primary key row does not exists")
}

Expand Down
48 changes: 35 additions & 13 deletions repository.go
Expand Up @@ -1030,25 +1030,47 @@ func (r repository) preload(cw contextWrapper, records slice, field string, quer
path = strings.Split(field, ".")
targets, table, keyField, keyType, ddata, loaded = r.mapPreloadTargets(records, path)
ids = r.targetIDs(targets)
query = Build(table, append(queriers, In(keyField, ids...))...)

inClauseLength = 999 // TODO: can this value come from the adapter, as it is dbms specific?
)

if len(targets) == 0 || loaded && !bool(query.ReloadQuery) {
return nil
}
// Create separate queries if the amount of ids is more than inClauseLength.
for {
if len(ids) == 0 {
break
}

var (
cur, err = cw.adapter.Query(cw.ctx, r.withDefaultScope(ddata, query, false))
)
// necessary check to avoid slicing beyond
// slice capacity
if len(ids) < inClauseLength {
inClauseLength = len(ids)
}

if err != nil {
return err
}
idsChunk := ids[0:inClauseLength]
ids = ids[inClauseLength:]

query := Build(table, append(queriers, In(keyField, idsChunk...))...)
if len(targets) == 0 || loaded && !bool(query.ReloadQuery) {
return nil
}

var (
cur, err = cw.adapter.Query(cw.ctx, r.withDefaultScope(ddata, query, false))
)

scanFinish := r.instrumenter.Observe(cw.ctx, "rel-scan-multi", "scanning all records to multiple targets")
defer scanFinish(nil)
if err != nil {
return err
}

return scanMulti(cur, keyField, keyType, targets)
scanFinish := r.instrumenter.Observe(cw.ctx, "rel-scan-multi", "scanning all records to multiple targets")
err = scanMulti(cur, keyField, keyType, targets)
scanFinish(nil)
if err != nil {
return err
}
}

return nil
}

func (r repository) MustPreload(ctx context.Context, records interface{}, field string, queriers ...Querier) {
Expand Down

0 comments on commit e3cd023

Please sign in to comment.