Optimize search3, by removing OFFSET when paginating (#2655)

* Optimize pagination, removing offset

* For search, don't add `where` clause for empty queries

* Revert "Replace `COUNT(DISTINCT primary_key)` with `COUNT(*)`"

Genres are required as part of the count queries, so filter by genres work

* Optimize search3 query, using order by id if it is a "" query.

Also fix the optimizePagination query logic

* Allow offset optimizer threshold to be configured
This commit is contained in:
Deluan Quintão
2023-11-27 13:06:23 -05:00
committed by GitHub
parent 28dc98dec4
commit 60a5fbe1fe
4 changed files with 38 additions and 8 deletions
+18 -1
View File
@@ -10,6 +10,7 @@ import (
. "github.com/Masterminds/squirrel"
"github.com/beego/beego/v2/client/orm"
"github.com/google/uuid"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/model/request"
@@ -157,7 +158,10 @@ func (r sqlRepository) queryOne(sq Sqlizer, response interface{}) error {
return err
}
func (r sqlRepository) queryAll(sq Sqlizer, response interface{}) error {
func (r sqlRepository) queryAll(sq SelectBuilder, response interface{}, options ...model.QueryOptions) error {
if len(options) > 0 && options[0].Offset > 0 {
sq = r.optimizePagination(sq, options[0])
}
query, args, err := sq.ToSql()
if err != nil {
return err
@@ -172,6 +176,19 @@ func (r sqlRepository) queryAll(sq Sqlizer, response interface{}) error {
return err
}
// optimizePagination uses a less inefficient pagination, by not using OFFSET.
// See https://gist.github.com/ssokolow/262503
func (r sqlRepository) optimizePagination(sq SelectBuilder, options model.QueryOptions) SelectBuilder {
if options.Offset > conf.Server.DevOffsetOptimize {
sq = sq.RemoveOffset()
oidSq := sq.RemoveColumns().Columns(r.tableName + ".oid")
oidSq = oidSq.Limit(uint64(options.Offset))
oidSql, args, _ := oidSq.ToSql()
sq = sq.Where(r.tableName+".oid not in ("+oidSql+")", args...)
}
return sq
}
func (r sqlRepository) exists(existsQuery SelectBuilder) (bool, error) {
existsQuery = existsQuery.Columns("count(*) as exist").From(r.tableName)
var res struct{ Exist int64 }