From d7439b48320c260dc257e41c65f40dfcd43f9748 Mon Sep 17 00:00:00 2001 From: gitgiggety <79809426+gitgiggety@users.noreply.github.com> Date: Mon, 21 Jun 2021 06:17:43 +0200 Subject: [PATCH] Optimize studio filter on performers (#1515) --- pkg/sqlite/performer.go | 61 ++++++++++++----------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/pkg/sqlite/performer.go b/pkg/sqlite/performer.go index e02a8525e..f04a6689f 100644 --- a/pkg/sqlite/performer.go +++ b/pkg/sqlite/performer.go @@ -458,80 +458,53 @@ func performerGalleryCountCriterionHandler(qb *performerQueryBuilder, count *mod func performerStudiosCriterionHandler(studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc { return func(f *filterBuilder) { if studios != nil { - var countCondition string - var clauseJoin string + var clauseCondition string if studios.Modifier == models.CriterionModifierIncludes { // return performers who appear in scenes/images/galleries with any of the given studios - countCondition = " > 0" - clauseJoin = " OR " + clauseCondition = "NOT" } else if studios.Modifier == models.CriterionModifierExcludes { // exclude performers who appear in scenes/images/galleries with any of the given studios - countCondition = " = 0" - clauseJoin = " AND " + clauseCondition = "" } else { return } - inBinding := getInBinding(len(studios.Value)) - formatMaps := []utils.StrFormatMap{ { "primaryTable": sceneTable, "joinTable": performersScenesTable, "primaryFK": sceneIDColumn, - "inBinding": inBinding, }, { "primaryTable": imageTable, "joinTable": performersImagesTable, "primaryFK": imageIDColumn, - "inBinding": inBinding, }, { "primaryTable": galleryTable, "joinTable": performersGalleriesTable, "primaryFK": galleryIDColumn, - "inBinding": inBinding, }, } - // keeping existing behaviour for depth = 0 since it seems slightly better performing - if studios.Depth == 0 { - templStr := `(SELECT COUNT(DISTINCT {primaryTable}.id) FROM {primaryTable} -LEFT JOIN {joinTable} ON {primaryTable}.id = {joinTable}.{primaryFK} -WHERE {joinTable}.performer_id = performers.id AND {primaryTable}.studio_id IN {inBinding})` + countCondition + const derivedStudioTable = "studio" + const derivedPerformerStudioTable = "performer_studio" + addHierarchicalWithClause(f, studios.Value, derivedStudioTable, studioTable, "parent_id", studios.Depth) - var clauses []string - for _, c := range formatMaps { - clauses = append(clauses, utils.StrFormat(templStr, c)) - } + templStr := `SELECT performer_id FROM {primaryTable} + INNER JOIN {joinTable} ON {primaryTable}.id = {joinTable}.{primaryFK} + INNER JOIN studio ON {primaryTable}.studio_id = studio.child_id` - var args []interface{} - for _, tagID := range studios.Value { - args = append(args, tagID) - } - - // this is a bit gross. We need the args three times - combinedArgs := append(args, append(args, args...)...) - - f.addWhere(fmt.Sprintf("(%s)", strings.Join(clauses, clauseJoin)), combinedArgs...) - } else { - const derivedTable = "studio" - addHierarchicalWithClause(f, studios.Value, derivedTable, studioTable, "parent_id", studios.Depth) - - templStr := `(SELECT COUNT(DISTINCT {primaryTable}.id) FROM {primaryTable} - LEFT JOIN {joinTable} ON {primaryTable}.id = {joinTable}.{primaryFK} - INNER JOIN studio ON {primaryTable}.studio_id = studio.child_id - WHERE {joinTable}.performer_id = performers.id)` + countCondition - - var clauses []string - for _, c := range formatMaps { - clauses = append(clauses, utils.StrFormat(templStr, c)) - } - - f.addWhere(fmt.Sprintf("(%s)", strings.Join(clauses, clauseJoin))) + var unions []string + for _, c := range formatMaps { + unions = append(unions, utils.StrFormat(templStr, c)) } + + f.addWith(fmt.Sprintf("%s AS (%s)", "performer_studio", strings.Join(unions, " UNION "))) + + f.addJoin(derivedPerformerStudioTable, "", fmt.Sprintf("performers.id = %s.performer_id", derivedPerformerStudioTable)) + f.addWhere(fmt.Sprintf("%s.performer_id IS %s NULL", derivedPerformerStudioTable, clauseCondition)) } } }