Skip to content

Commit

Permalink
Fix AddJoinTableFilter performance (stashapp#689)
Browse files Browse the repository at this point in the history
  • Loading branch information
InfiniteStash authored and feederbox826 committed Nov 15, 2023
1 parent ac7abfd commit 9f09751
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 57 deletions.
20 changes: 10 additions & 10 deletions pkg/sqlx/querybuilder_edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,6 @@ func (qb *editQueryBuilder) buildQuery(filter models.EditQueryInput, userID uuid
query.Eq("target_type", q.String())
}

if q := filter.Status; q != nil {
query.Eq("status", q.String())
}
if q := filter.Operation; q != nil {
query.Eq("operation", q.String())
}
if q := filter.Applied; q != nil {
query.Eq("applied", *q)
}

if q := filter.Voted; q != nil && *q != "" {
switch *filter.Voted {
case models.UserVotedFilterEnumNotVoted:
Expand Down Expand Up @@ -288,6 +278,16 @@ func (qb *editQueryBuilder) buildQuery(filter models.EditQueryInput, userID uuid
query.AddArg(userID, userID, userID, userID, userID, userID)
}

if q := filter.Status; q != nil {
query.Eq("status", q.String())
}
if q := filter.Operation; q != nil {
query.Eq("operation", q.String())
}
if q := filter.Applied; q != nil {
query.Eq("applied", *q)
}

if q := filter.IsBot; q != nil {
query.Eq("bot", *q)
}
Expand Down
82 changes: 41 additions & 41 deletions pkg/sqlx/querybuilder_scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,47 @@ func (qb *sceneQueryBuilder) Count() (int, error) {
func (qb *sceneQueryBuilder) buildQuery(filter models.SceneQueryInput, userID uuid.UUID, isCount bool) (*queryBuilder, error) {
query := newQueryBuilder(sceneDBTable)

if q := filter.URL; q != nil && *q != "" {
where := fmt.Sprintf("%s.url = ?", sceneURLTable.Name())
query.AddJoinTableFilter(sceneURLTable, where, nil, false, *q)
}

if filter.ParentStudio != nil {
query.Body += "LEFT JOIN studios ON scenes.studio_id = studios.id"
query.AddWhere("(studios.parent_studio_id = ? OR studios.id = ?)")
query.AddArg(*filter.ParentStudio, *filter.ParentStudio)
}

if q := filter.Performers; q != nil && len(q.Value) > 0 {
if err := setMultiCriterionClause(query, scenePerformerTable, performerJoinKey, q); err != nil {
return nil, err
}
}

if q := filter.Tags; q != nil && len(q.Value) > 0 {
if err := setMultiCriterionClause(query, sceneTagTable, tagJoinKey, q); err != nil {
return nil, err
}
}

if q := filter.Fingerprints; q != nil && len(q.Value) > 0 {
if err := setMultiCriterionClause(query, sceneFingerprintTable, "hash", q); err != nil {
return nil, err
}
}

if filter.HasFingerprintSubmissions != nil && *filter.HasFingerprintSubmissions {
query.Body += `
JOIN (
SELECT scene_id
FROM scene_fingerprints
WHERE user_id = ?
GROUP BY scene_id
) T ON scenes.id = T.scene_id
`
query.AddArg(userID)
}

if q := filter.Text; q != nil && *q != "" {
searchColumns := []string{"scenes.title", "scenes.details"}
clause, thisArgs := getSearchBinding(searchColumns, *q, false, false)
Expand All @@ -359,11 +400,6 @@ func (qb *sceneQueryBuilder) buildQuery(filter models.SceneQueryInput, userID uu
query.AddArg(thisArgs...)
}

if q := filter.URL; q != nil && *q != "" {
where := fmt.Sprintf("%s.url = ?", sceneURLTable.Name())
query.AddJoinTableFilter(sceneURLTable, where, nil, false, *q)
}

if q := filter.Studios; q != nil && len(q.Value) > 0 {
column := "scenes.studio_id"

Expand Down Expand Up @@ -395,30 +431,6 @@ func (qb *sceneQueryBuilder) buildQuery(filter models.SceneQueryInput, userID uu
}
}

if filter.ParentStudio != nil {
query.Body += "LEFT JOIN studios ON scenes.studio_id = studios.id"
query.AddWhere("(studios.parent_studio_id = ? OR studios.id = ?)")
query.AddArg(*filter.ParentStudio, *filter.ParentStudio)
}

if q := filter.Performers; q != nil && len(q.Value) > 0 {
if err := setMultiCriterionClause(query, scenePerformerTable, performerJoinKey, q); err != nil {
return nil, err
}
}

if q := filter.Tags; q != nil && len(q.Value) > 0 {
if err := setMultiCriterionClause(query, sceneTagTable, tagJoinKey, q); err != nil {
return nil, err
}
}

if q := filter.Fingerprints; q != nil && len(q.Value) > 0 {
if err := setMultiCriterionClause(query, sceneFingerprintTable, "hash", q); err != nil {
return nil, err
}
}

if q := filter.Favorites; q != nil {
var clauses []string
if *q == models.FavoriteFilterPerformer || *q == models.FavoriteFilterAll {
Expand Down Expand Up @@ -467,18 +479,6 @@ func (qb *sceneQueryBuilder) buildQuery(filter models.SceneQueryInput, userID uu
query.Pagination = getPagination(filter.Page, filter.PerPage)
}

if filter.HasFingerprintSubmissions != nil && *filter.HasFingerprintSubmissions {
query.Body += `
JOIN (
SELECT scene_id
FROM scene_fingerprints
WHERE user_id = ?
GROUP BY scene_id
) T ON scenes.id = T.scene_id
`
query.AddArg(userID)
}

query.Eq("scenes.deleted", false)

return query, nil
Expand Down
4 changes: 2 additions & 2 deletions pkg/sqlx/querybuilder_studio.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,6 @@ func (qb *studioQueryBuilder) Query(filter models.StudioQueryInput, userID uuid.
query := newQueryBuilder(studioDBTable)
query.Body += "LEFT JOIN studios as parent_studio ON studios.parent_studio_id = parent_studio.id"

query.Eq("studios.deleted", false)

if q := filter.Name; q != nil && *q != "" {
searchColumns := []string{"studios.name"}
clause, thisArgs := getSearchBinding(searchColumns, *q, false, true)
Expand Down Expand Up @@ -214,6 +212,8 @@ func (qb *studioQueryBuilder) Query(filter models.StudioQueryInput, userID uuid.
query.Sort = qb.getStudioSort(filter)
query.Pagination = getPagination(filter.Page, filter.PerPage)

query.Eq("studios.deleted", false)

var studios models.Studios
countResult, err := qb.dbi.Query(*query, &studios)

Expand Down
9 changes: 5 additions & 4 deletions pkg/sqlx/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (qb *queryBuilder) AddJoin(jt table, on string) {
}

func (qb *queryBuilder) AddJoinTableFilter(tj tableJoin, query string, having *string, not bool, args ...interface{}) {
clause := fmt.Sprintf("EXISTS (SELECT %[1]s.%[2]s FROM %[1]s WHERE %[3]s.id = %[1]s.%[2]s AND %[4]s", tj.Name(), tj.joinColumn, tj.primaryTable, query)
clause := fmt.Sprintf(" JOIN (SELECT %[1]s.%[2]s FROM %[1]s WHERE %[3]s", tj.Name(), tj.joinColumn, query)
if len(args) > 1 {
clause += fmt.Sprintf(" GROUP BY %s.%s", tj.Name(), tj.joinColumn)

Expand All @@ -58,13 +58,14 @@ func (qb *queryBuilder) AddJoinTableFilter(tj tableJoin, query string, having *s
}
}

clause += ")"
clause += fmt.Sprintf(") %[1]s ON %[3]s.id = %[1]s.%[2]s", tj.Name(), tj.joinColumn, tj.primaryTable)

if not {
clause = "NOT " + clause
clause = " LEFT" + clause
qb.AddWhere(fmt.Sprintf("%s.%s IS NULL", tj.Name(), tj.joinColumn))
}

qb.AddWhere(clause)
qb.Body += clause
qb.AddArg(args...)
}

Expand Down

0 comments on commit 9f09751

Please sign in to comment.