mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2026-09-03 20:53:09 -05:00
Video SQL query optimization
Reduce number of rows to parse in NodeJS by generating the JSON directly in PostgreSQL
This commit is contained in:
@@ -283,7 +283,7 @@ async function prepare () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
servers = await Promise.all([
|
servers = await Promise.all([
|
||||||
createSingleServer(1, config, { nodeArgs: [ '--inspect' ] }),
|
createSingleServer(1, config, { nodeArgs: [ '--inspect=9230' ] }),
|
||||||
createSingleServer(2, config),
|
createSingleServer(2, config),
|
||||||
createSingleServer(3, config)
|
createSingleServer(3, config)
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -45,9 +45,14 @@ export class AbstractVideoQueryBuilder extends AbstractRunQuery {
|
|||||||
)
|
)
|
||||||
|
|
||||||
this.addJoin(
|
this.addJoin(
|
||||||
'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Actor->Avatars" ' +
|
`LEFT JOIN LATERAL (` +
|
||||||
'ON "VideoChannel->Actor"."id" = "VideoChannel->Actor->Avatars"."actorId" ' +
|
`SELECT json_agg(` +
|
||||||
`AND "VideoChannel->Actor->Avatars"."type" = ${ActorImageType.AVATAR}`
|
` jsonb_build_object(` +
|
||||||
|
` ` + this.tables.getAvatarAttributes().map(attr => `'${attr}', "${attr}"`).join(', ') +
|
||||||
|
` )` +
|
||||||
|
`) AS "Avatars"` +
|
||||||
|
` FROM "actorImage" WHERE "actorId" = "VideoChannel->Actor"."id" AND "type" = ${ActorImageType.AVATAR}` +
|
||||||
|
`) AS "VideoChannel->Actor->AvatarsJSON" ON TRUE`
|
||||||
)
|
)
|
||||||
|
|
||||||
this.attributes = {
|
this.attributes = {
|
||||||
@@ -55,7 +60,7 @@ export class AbstractVideoQueryBuilder extends AbstractRunQuery {
|
|||||||
|
|
||||||
...this.buildAttributesObject('VideoChannel', this.tables.getChannelAttributes()),
|
...this.buildAttributesObject('VideoChannel', this.tables.getChannelAttributes()),
|
||||||
...this.buildActorInclude('VideoChannel->Actor'),
|
...this.buildActorInclude('VideoChannel->Actor'),
|
||||||
...this.buildAvatarInclude('VideoChannel->Actor->Avatars'),
|
'"VideoChannel->Actor->AvatarsJSON"."Avatars"': '"VideoChannel.Actor.AvatarsJSON"',
|
||||||
...this.buildServerInclude('VideoChannel->Actor->Server')
|
...this.buildServerInclude('VideoChannel->Actor->Server')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,9 +77,14 @@ export class AbstractVideoQueryBuilder extends AbstractRunQuery {
|
|||||||
)
|
)
|
||||||
|
|
||||||
this.addJoin(
|
this.addJoin(
|
||||||
'LEFT OUTER JOIN "actorImage" AS "VideoChannel->Account->Actor->Avatars" ' +
|
`LEFT JOIN LATERAL (` +
|
||||||
'ON "VideoChannel->Account->Actor"."id" = "VideoChannel->Account->Actor->Avatars"."actorId" ' +
|
`SELECT json_agg(` +
|
||||||
`AND "VideoChannel->Account->Actor->Avatars"."type" = ${ActorImageType.AVATAR}`
|
` jsonb_build_object(` +
|
||||||
|
` ` + this.tables.getAvatarAttributes().map(attr => `'${attr}', "${attr}"`).join(', ') +
|
||||||
|
` )` +
|
||||||
|
`) AS "Avatars"` +
|
||||||
|
` FROM "actorImage" WHERE "actorId" = "VideoChannel->Account->Actor"."id" AND "type" = ${ActorImageType.AVATAR}` +
|
||||||
|
`) AS "VideoChannel->Account->Actor->AvatarsJSON" ON TRUE`
|
||||||
)
|
)
|
||||||
|
|
||||||
this.attributes = {
|
this.attributes = {
|
||||||
@@ -82,18 +92,26 @@ export class AbstractVideoQueryBuilder extends AbstractRunQuery {
|
|||||||
|
|
||||||
...this.buildAttributesObject('VideoChannel->Account', this.tables.getAccountAttributes()),
|
...this.buildAttributesObject('VideoChannel->Account', this.tables.getAccountAttributes()),
|
||||||
...this.buildActorInclude('VideoChannel->Account->Actor'),
|
...this.buildActorInclude('VideoChannel->Account->Actor'),
|
||||||
...this.buildAvatarInclude('VideoChannel->Account->Actor->Avatars'),
|
'"VideoChannel->Account->Actor->AvatarsJSON"."Avatars"': '"VideoChannel.Account.Actor.AvatarsJSON"',
|
||||||
...this.buildServerInclude('VideoChannel->Account->Actor->Server')
|
...this.buildServerInclude('VideoChannel->Account->Actor->Server')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected includeThumbnails () {
|
protected includeThumbnailsJSON () {
|
||||||
this.addJoin('LEFT OUTER JOIN "thumbnail" AS "Thumbnails" ON "video"."id" = "Thumbnails"."videoId"')
|
this.addJoin(
|
||||||
|
` LEFT JOIN LATERAL (` +
|
||||||
|
` SELECT json_agg(` +
|
||||||
|
` jsonb_build_object(` +
|
||||||
|
` ` + this.tables.getThumbnailAttributes().map(attr => `'${attr}', "${attr}"`).join(', ') +
|
||||||
|
` )` +
|
||||||
|
` ) AS "thumbnails" FROM "thumbnail" WHERE "videoId" = "video"."id"` +
|
||||||
|
`) AS "ThumbnailsJSON" ON TRUE`
|
||||||
|
)
|
||||||
|
|
||||||
this.attributes = {
|
this.attributes = {
|
||||||
...this.attributes,
|
...this.attributes,
|
||||||
|
|
||||||
...this.buildAttributesObject('Thumbnails', this.tables.getThumbnailAttributes())
|
'"ThumbnailsJSON"."thumbnails"': '"ThumbnailsJSON"'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -268,28 +268,29 @@ export class VideoModelBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private addActorAvatar (row: SQLRow, actorPrefix: string, actor: ActorModel) {
|
private addActorAvatar (row: SQLRow, actorPrefix: string, actor: ActorModel) {
|
||||||
const avatarPrefix = `${actorPrefix}.Avatars`
|
const key = `${actorPrefix}${row.id}`
|
||||||
const id = row[`${avatarPrefix}.id`]
|
if (this.actorImagesDone.has(key)) return
|
||||||
const key = `${row.id}${id}`
|
|
||||||
|
|
||||||
if (!id || this.actorImagesDone.has(key)) return
|
|
||||||
|
|
||||||
const attributes = this.grab(row, this.tables.getAvatarAttributes(), avatarPrefix)
|
|
||||||
const avatarModel = new ActorImageModel(attributes, this.buildOpts)
|
|
||||||
actor.Avatars.push(avatarModel)
|
|
||||||
|
|
||||||
this.actorImagesDone.add(key)
|
this.actorImagesDone.add(key)
|
||||||
|
|
||||||
|
const avatars = row[`${actorPrefix}.AvatarsJSON`] as any || []
|
||||||
|
for (const avatar of avatars) {
|
||||||
|
const avatarModel = new ActorImageModel(avatar, this.buildOpts)
|
||||||
|
actor.Avatars.push(avatarModel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addThumbnail (row: SQLRow, videoModel: VideoModel) {
|
private addThumbnail (row: SQLRow, videoModel: VideoModel) {
|
||||||
const id = row['Thumbnails.id']
|
if (this.thumbnailsDone.has(videoModel.id)) return
|
||||||
if (!id || this.thumbnailsDone.has(id)) return
|
|
||||||
|
|
||||||
const attributes = this.grab(row, this.tables.getThumbnailAttributes(), 'Thumbnails')
|
const thumbnails = row['ThumbnailsJSON'] as any || []
|
||||||
const thumbnailModel = new ThumbnailModel(attributes, this.buildOpts)
|
|
||||||
videoModel.Thumbnails.push(thumbnailModel)
|
|
||||||
|
|
||||||
this.thumbnailsDone.add(id)
|
for (const thumbnail of thumbnails) {
|
||||||
|
const thumbnailModel = new ThumbnailModel(thumbnail, this.buildOpts)
|
||||||
|
|
||||||
|
videoModel.Thumbnails.push(thumbnailModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.thumbnailsDone.add(videoModel.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private addWebVideoFile (row: SQLRow, videoModel: VideoModel) {
|
private addWebVideoFile (row: SQLRow, videoModel: VideoModel) {
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export class VideosModelGetQuerySubBuilder extends AbstractVideoQueryBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (thumbnailsInclude.has(options.type)) {
|
if (thumbnailsInclude.has(options.type)) {
|
||||||
this.includeThumbnails()
|
this.includeThumbnailsJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blacklistedInclude.has(options.type)) {
|
if (blacklistedInclude.has(options.type)) {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export class VideosModelListQueryBuilder extends AbstractVideoQueryBuilder {
|
|||||||
|
|
||||||
this.includeChannels()
|
this.includeChannels()
|
||||||
this.includeAccounts()
|
this.includeAccounts()
|
||||||
this.includeThumbnails()
|
this.includeThumbnailsJSON()
|
||||||
|
|
||||||
if (options.user) {
|
if (options.user) {
|
||||||
this.includeUserHistory(options.user.id)
|
this.includeUserHistory(options.user.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user