Skip to content

Commit

Permalink
perf: refactor SelectQuery.ScanAndCount to optimize performance when …
Browse files Browse the repository at this point in the history
…there is no limit and offset (#1035)
  • Loading branch information
Tiscs authored Oct 26, 2024
1 parent a3ccbea commit 8638613
Showing 1 changed file with 24 additions and 9 deletions.
33 changes: 24 additions & 9 deletions query_select.go
Original file line number Diff line number Diff line change
Expand Up @@ -856,52 +856,57 @@ func (q *SelectQuery) Exec(ctx context.Context, dest ...interface{}) (res sql.Re
}

func (q *SelectQuery) Scan(ctx context.Context, dest ...interface{}) error {
_, err := q.scanResult(ctx, dest...)
return err
}

func (q *SelectQuery) scanResult(ctx context.Context, dest ...interface{}) (sql.Result, error) {
if q.err != nil {
return q.err
return nil, q.err
}

model, err := q.getModel(dest)
if err != nil {
return err
return nil, err
}

if q.table != nil {
if err := q.beforeSelectHook(ctx); err != nil {
return err
return nil, err
}
}

if err := q.beforeAppendModel(ctx, q); err != nil {
return err
return nil, err
}

queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes())
if err != nil {
return err
return nil, err
}

query := internal.String(queryBytes)

res, err := q.scan(ctx, q, query, model, true)
if err != nil {
return err
return nil, err
}

if n, _ := res.RowsAffected(); n > 0 {
if tableModel, ok := model.(TableModel); ok {
if err := q.selectJoins(ctx, tableModel.getJoins()); err != nil {
return err
return nil, err
}
}
}

if q.table != nil {
if err := q.afterSelectHook(ctx); err != nil {
return err
return nil, err
}
}

return nil
return res, nil
}

func (q *SelectQuery) beforeSelectHook(ctx context.Context) error {
Expand Down Expand Up @@ -946,6 +951,16 @@ func (q *SelectQuery) Count(ctx context.Context) (int, error) {
}

func (q *SelectQuery) ScanAndCount(ctx context.Context, dest ...interface{}) (int, error) {
if q.offset == 0 && q.limit == 0 {
// If there is no limit and offset, we can use a single query to get the count and scan
if res, err := q.scanResult(ctx, dest...); err != nil {
return 0, err
} else if n, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return int(n), nil
}
}
if _, ok := q.conn.(*DB); ok {
return q.scanAndCountConc(ctx, dest...)
}
Expand Down

0 comments on commit 8638613

Please sign in to comment.