Optimize feeds query

pull/5098/head
Chocobozzz 2022-06-27 09:34:26 +02:00
parent c53853ca1b
commit 7fb45bdacb
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
4 changed files with 69 additions and 24 deletions

View File

@ -313,7 +313,12 @@ export class AbstractVideoQueryBuilder extends AbstractRunQuery {
return result return result
} }
protected whereId (options: { id?: string | number, url?: string }) { protected whereId (options: { ids?: number[], id?: string | number, url?: string }) {
if (options.ids) {
this.where = `WHERE "video"."id" IN (${createSafeIn(this.sequelize, options.ids)})`
return
}
if (options.url) { if (options.url) {
this.where = 'WHERE "video"."url" = :videoUrl' this.where = 'WHERE "video"."url" = :videoUrl'
this.replacements.videoUrl = options.url this.replacements.videoUrl = options.url

View File

@ -1,7 +1,17 @@
import { Sequelize } from 'sequelize' import { Sequelize, Transaction } from 'sequelize'
import { BuildVideoGetQueryOptions } from '../video-model-get-query-builder'
import { AbstractVideoQueryBuilder } from './abstract-video-query-builder' import { AbstractVideoQueryBuilder } from './abstract-video-query-builder'
export type FileQueryOptions = {
id?: string | number
url?: string
includeRedundancy: boolean
transaction?: Transaction
logging?: boolean
}
/** /**
* *
* Fetch files (webtorrent and streaming playlist) according to a video * Fetch files (webtorrent and streaming playlist) according to a video
@ -15,26 +25,26 @@ export class VideoFileQueryBuilder extends AbstractVideoQueryBuilder {
super(sequelize, 'get') super(sequelize, 'get')
} }
queryWebTorrentVideos (options: BuildVideoGetQueryOptions) { queryWebTorrentVideos (options: FileQueryOptions) {
this.buildWebtorrentFilesQuery(options) this.buildWebtorrentFilesQuery(options)
return this.runQuery(options) return this.runQuery(options)
} }
queryStreamingPlaylistVideos (options: BuildVideoGetQueryOptions) { queryStreamingPlaylistVideos (options: FileQueryOptions) {
this.buildVideoStreamingPlaylistFilesQuery(options) this.buildVideoStreamingPlaylistFilesQuery(options)
return this.runQuery(options) return this.runQuery(options)
} }
private buildWebtorrentFilesQuery (options: BuildVideoGetQueryOptions) { private buildWebtorrentFilesQuery (options: FileQueryOptions) {
this.attributes = { this.attributes = {
'"video"."id"': '' '"video"."id"': ''
} }
this.includeWebtorrentFiles() this.includeWebtorrentFiles()
if (this.shouldIncludeRedundancies(options)) { if (options.includeRedundancy) {
this.includeWebTorrentRedundancies() this.includeWebTorrentRedundancies()
} }
@ -43,14 +53,14 @@ export class VideoFileQueryBuilder extends AbstractVideoQueryBuilder {
this.query = this.buildQuery() this.query = this.buildQuery()
} }
private buildVideoStreamingPlaylistFilesQuery (options: BuildVideoGetQueryOptions) { private buildVideoStreamingPlaylistFilesQuery (options: FileQueryOptions) {
this.attributes = { this.attributes = {
'"video"."id"': '' '"video"."id"': ''
} }
this.includeStreamingPlaylistFiles() this.includeStreamingPlaylistFiles()
if (this.shouldIncludeRedundancies(options)) { if (options.includeRedundancy) {
this.includeStreamingPlaylistRedundancies() this.includeStreamingPlaylistRedundancies()
} }
@ -62,8 +72,4 @@ export class VideoFileQueryBuilder extends AbstractVideoQueryBuilder {
private buildQuery () { private buildQuery () {
return `${this.buildSelect()} FROM "video" ${this.joins} ${this.where}` return `${this.buildSelect()} FROM "video" ${this.joins} ${this.where}`
} }
private shouldIncludeRedundancies (options: BuildVideoGetQueryOptions) {
return options.type === 'api'
}
} }

View File

@ -1,3 +1,4 @@
import { pick } from 'lodash'
import { Sequelize, Transaction } from 'sequelize' import { Sequelize, Transaction } from 'sequelize'
import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder' import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder'
import { VideoFileQueryBuilder } from './shared/video-file-query-builder' import { VideoFileQueryBuilder } from './shared/video-file-query-builder'
@ -50,15 +51,21 @@ export class VideoModelGetQueryBuilder {
} }
async queryVideo (options: BuildVideoGetQueryOptions) { async queryVideo (options: BuildVideoGetQueryOptions) {
const fileQueryOptions = {
...pick(options, [ 'id', 'url', 'transaction', 'logging' ]),
includeRedundancy: this.shouldIncludeRedundancies(options)
}
const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([ const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([
this.videoQueryBuilder.queryVideos(options), this.videoQueryBuilder.queryVideos(options),
VideoModelGetQueryBuilder.videoFilesInclude.has(options.type) VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options) ? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(fileQueryOptions)
: Promise.resolve(undefined), : Promise.resolve(undefined),
VideoModelGetQueryBuilder.videoFilesInclude.has(options.type) VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options) ? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(fileQueryOptions)
: Promise.resolve(undefined) : Promise.resolve(undefined)
]) ])
@ -76,6 +83,10 @@ export class VideoModelGetQueryBuilder {
return videos[0] return videos[0]
} }
private shouldIncludeRedundancies (options: BuildVideoGetQueryOptions) {
return options.type === 'api'
}
} }
export class VideosModelGetQuerySubBuilder extends AbstractVideoQueryBuilder { export class VideosModelGetQuerySubBuilder extends AbstractVideoQueryBuilder {

View File

@ -1,6 +1,8 @@
import { VideoInclude } from '@shared/models' import { pick } from 'lodash'
import { Sequelize } from 'sequelize' import { Sequelize } from 'sequelize'
import { VideoInclude } from '@shared/models'
import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder' import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder'
import { VideoFileQueryBuilder } from './shared/video-file-query-builder'
import { VideoModelBuilder } from './shared/video-model-builder' import { VideoModelBuilder } from './shared/video-model-builder'
import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './videos-id-list-query-builder' import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './videos-id-list-query-builder'
@ -16,20 +18,46 @@ export class VideosModelListQueryBuilder extends AbstractVideoQueryBuilder {
private innerQuery: string private innerQuery: string
private innerSort: string private innerSort: string
webtorrentFilesQueryBuilder: VideoFileQueryBuilder
streamingPlaylistFilesQueryBuilder: VideoFileQueryBuilder
private readonly videoModelBuilder: VideoModelBuilder private readonly videoModelBuilder: VideoModelBuilder
constructor (protected readonly sequelize: Sequelize) { constructor (protected readonly sequelize: Sequelize) {
super(sequelize, 'list') super(sequelize, 'list')
this.videoModelBuilder = new VideoModelBuilder(this.mode, this.tables) this.videoModelBuilder = new VideoModelBuilder(this.mode, this.tables)
this.webtorrentFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
this.streamingPlaylistFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
} }
queryVideos (options: BuildVideosListQueryOptions) { async queryVideos (options: BuildVideosListQueryOptions) {
this.buildInnerQuery(options) this.buildInnerQuery(options)
this.buildMainQuery(options) this.buildMainQuery(options)
return this.runQuery() const rows = await this.runQuery()
.then(rows => this.videoModelBuilder.buildVideosFromRows({ rows, include: options.include }))
if (options.include & VideoInclude.FILES) {
const videoIds = Array.from(new Set(rows.map(r => r.id)))
if (videoIds.length !== 0) {
const fileQueryOptions = {
...pick(options, [ 'transaction', 'logging' ]),
ids: videoIds,
includeRedundancy: false
}
const [ rowsWebTorrentFiles, rowsStreamingPlaylist ] = await Promise.all([
this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(fileQueryOptions),
this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(fileQueryOptions)
])
return this.videoModelBuilder.buildVideosFromRows({ rows, include: options.include, rowsStreamingPlaylist, rowsWebTorrentFiles })
}
}
return this.videoModelBuilder.buildVideosFromRows({ rows, include: options.include })
} }
private buildInnerQuery (options: BuildVideosListQueryOptions) { private buildInnerQuery (options: BuildVideosListQueryOptions) {
@ -52,11 +80,6 @@ export class VideosModelListQueryBuilder extends AbstractVideoQueryBuilder {
this.includeAccounts() this.includeAccounts()
this.includeThumbnails() this.includeThumbnails()
if (options.include & VideoInclude.FILES) {
this.includeWebtorrentFiles()
this.includeStreamingPlaylistFiles()
}
if (options.user) { if (options.user) {
this.includeUserHistory(options.user.id) this.includeUserHistory(options.user.id)
} }