Omit joins that are only used for sorting when skipping sorting

Should provide some marginal improvement on systems with a lot of items.
This commit is contained in:
WithoutPants 2025-12-05 17:19:43 +11:00
parent 7d96169796
commit ff360ba5b1
7 changed files with 50 additions and 13 deletions

View file

@ -96,6 +96,9 @@ type join struct {
onClause string
joinType string
args []interface{}
// if true, indicates this is required for sorting only
sort bool
}
// equals returns true if the other join alias/table is equal to this one
@ -131,9 +134,13 @@ type joins []join
// returns true if added
func (j *joins) addUnique(newJoin join) bool {
found := false
for _, jj := range *j {
for i, jj := range *j {
if jj.equals(newJoin) {
found = true
// if sort is false on the new join, but true on the existing, set the false
if !newJoin.sort && jj.sort {
(*j)[i].sort = false
}
break
}
}
@ -151,13 +158,17 @@ func (j *joins) add(newJoins ...join) {
}
}
func (j *joins) toSQL() string {
func (j *joins) toSQL(includeSortPagination bool) string {
if len(*j) == 0 {
return ""
}
var ret []string
for _, jj := range *j {
// skip sort-only joins if not including sort/pagination
if !includeSortPagination && jj.sort {
continue
}
ret = append(ret, jj.toSQL())
}

View file

@ -800,10 +800,12 @@ func (qb *GalleryStore) setGallerySort(query *queryBuilder, findFilter *models.F
addFileTable := func() {
query.addJoins(
join{
sort: true,
table: galleriesFilesTable,
onClause: "galleries_files.gallery_id = galleries.id",
},
join{
sort: true,
table: fileTable,
onClause: "galleries_files.file_id = files.id",
},
@ -813,10 +815,12 @@ func (qb *GalleryStore) setGallerySort(query *queryBuilder, findFilter *models.F
addFolderTable := func() {
query.addJoins(
join{
sort: true,
table: folderTable,
onClause: "folders.id = galleries.folder_id",
},
join{
sort: true,
table: folderTable,
as: "file_folder",
onClause: "files.parent_folder_id = file_folder.id",

View file

@ -518,7 +518,7 @@ func (qb *GroupStore) setGroupSort(query *queryBuilder, findFilter *models.FindF
} else {
// this will give unexpected results if the query is not filtered by a parent group and
// the group has multiple parents and order indexes
query.join(groupRelationsTable, "", "groups.id = groups_relations.sub_id")
query.joinSort(groupRelationsTable, "", "groups.id = groups_relations.sub_id")
query.sortAndPagination += getSort("order_index", direction, groupRelationsTable)
}
case "tag_count":

View file

@ -965,10 +965,12 @@ func (qb *ImageStore) setImageSortAndPagination(q *queryBuilder, findFilter *mod
addFilesJoin := func() {
q.addJoins(
join{
sort: true,
table: imagesFilesTable,
onClause: "images_files.image_id = images.id",
},
join{
sort: true,
table: fileTable,
onClause: "images_files.file_id = files.id",
},
@ -977,6 +979,7 @@ func (qb *ImageStore) setImageSortAndPagination(q *queryBuilder, findFilter *mod
addFolderJoin := func() {
q.addJoins(join{
sort: true,
table: folderTable,
onClause: "files.parent_folder_id = folders.id",
})

View file

@ -24,8 +24,8 @@ type queryBuilder struct {
sortAndPagination string
}
func (qb queryBuilder) body() string {
return fmt.Sprintf("SELECT %s FROM %s%s", strings.Join(qb.columns, ", "), qb.from, qb.joins.toSQL())
func (qb queryBuilder) body(includeSortPagination bool) string {
return fmt.Sprintf("SELECT %s FROM %s%s", strings.Join(qb.columns, ", "), qb.from, qb.joins.toSQL(includeSortPagination))
}
func (qb *queryBuilder) addColumn(column string) {
@ -33,7 +33,7 @@ func (qb *queryBuilder) addColumn(column string) {
}
func (qb queryBuilder) toSQL(includeSortPagination bool) string {
body := qb.body()
body := qb.body(includeSortPagination)
withClause := ""
if len(qb.withClauses) > 0 {
@ -59,12 +59,14 @@ func (qb queryBuilder) findIDs(ctx context.Context) ([]int, error) {
}
func (qb queryBuilder) executeFind(ctx context.Context) ([]int, int, error) {
body := qb.body()
const includeSortPagination = true
body := qb.body(includeSortPagination)
return qb.repository.executeFindQuery(ctx, body, qb.args, qb.sortAndPagination, qb.whereClauses, qb.havingClauses, qb.withClauses, qb.recursiveWith)
}
func (qb queryBuilder) executeCount(ctx context.Context) (int, error) {
body := qb.body()
const includeSortPagination = false
body := qb.body(includeSortPagination)
withClause := ""
if len(qb.withClauses) > 0 {
@ -131,6 +133,18 @@ func (qb *queryBuilder) join(table, as, onClause string) {
qb.joins.add(newJoin)
}
func (qb *queryBuilder) joinSort(table, as, onClause string) {
newJoin := join{
sort: true,
table: table,
as: as,
onClause: onClause,
joinType: "LEFT",
}
qb.joins.add(newJoin)
}
func (qb *queryBuilder) addJoins(joins ...join) {
for _, j := range joins {
if qb.joins.addUnique(j) {

View file

@ -1157,10 +1157,12 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
addFileTable := func() {
query.addJoins(
join{
sort: true,
table: scenesFilesTable,
onClause: "scenes_files.scene_id = scenes.id",
},
join{
sort: true,
table: fileTable,
onClause: "scenes_files.file_id = files.id",
},
@ -1171,6 +1173,7 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
addFileTable()
query.addJoins(
join{
sort: true,
table: videoFileTable,
onClause: "video_files.file_id = scenes_files.file_id",
},
@ -1180,6 +1183,7 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
addFolderTable := func() {
query.addJoins(
join{
sort: true,
table: folderTable,
onClause: "files.parent_folder_id = folders.id",
},
@ -1189,10 +1193,10 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
direction := findFilter.GetDirection()
switch sort {
case "movie_scene_number":
query.join(groupsScenesTable, "", "scenes.id = groups_scenes.scene_id")
query.joinSort(groupsScenesTable, "", "scenes.id = groups_scenes.scene_id")
query.sortAndPagination += getSort("scene_index", direction, groupsScenesTable)
case "group_scene_number":
query.join(groupsScenesTable, "scene_group", "scenes.id = scene_group.scene_id")
query.joinSort(groupsScenesTable, "scene_group", "scenes.id = scene_group.scene_id")
query.sortAndPagination += getSort("scene_index", direction, "scene_group")
case "tag_count":
query.sortAndPagination += getCountSort(sceneTable, scenesTagsTable, sceneIDColumn, direction)
@ -1210,6 +1214,7 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
addFileTable()
query.addJoins(
join{
sort: true,
table: fingerprintTable,
as: "fingerprints_phash",
onClause: "scenes_files.file_id = fingerprints_phash.file_id AND fingerprints_phash.type = 'phash'",
@ -1274,7 +1279,7 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
getSortDirection(direction),
)
case "studio":
query.join(studioTable, "", "scenes.studio_id = studios.id")
query.joinSort(studioTable, "", "scenes.studio_id = studios.id")
query.sortAndPagination += getSort("name", direction, studioTable)
default:
query.sortAndPagination += getSort(sort, direction, "scenes")

View file

@ -392,10 +392,10 @@ func (qb *SceneMarkerStore) setSceneMarkerSort(query *queryBuilder, findFilter *
switch sort {
case "scenes_updated_at":
sort = "updated_at"
query.join(sceneTable, "", "scenes.id = scene_markers.scene_id")
query.joinSort(sceneTable, "", "scenes.id = scene_markers.scene_id")
query.sortAndPagination += getSort(sort, direction, sceneTable)
case "title":
query.join(tagTable, "", "scene_markers.primary_tag_id = tags.id")
query.joinSort(tagTable, "", "scene_markers.primary_tag_id = tags.id")
query.sortAndPagination += " ORDER BY COALESCE(NULLIF(scene_markers.title,''), tags.name) COLLATE NATURAL_CI " + direction
case "duration":
sort = "(scene_markers.end_seconds - scene_markers.seconds)"