perf(backend): avoid N+1 selects from user table when packing many entities (#13911)

* perf(backend): avoid N+1 selects from `user` table when packing many entities

* perf(backend): use `packMany` instead of mapping to `pack`
This commit is contained in:
zyoshoka
2024-05-31 15:32:42 +09:00
committed by GitHub
parent 97be1a53ad
commit 514a65e453
24 changed files with 268 additions and 87 deletions

View File

@@ -222,6 +222,9 @@ export class DriveFileEntityService {
public async packNullable(
src: MiDriveFile['id'] | MiDriveFile,
options?: PackOptions,
hint?: {
packedUser?: Packed<'UserLite'>
},
): Promise<Packed<'DriveFile'> | null> {
const opts = Object.assign({
detail: false,
@@ -249,7 +252,7 @@ export class DriveFileEntityService {
detail: true,
}) : null,
userId: file.userId,
user: (opts.withUser && file.userId) ? this.userEntityService.pack(file.userId) : null,
user: (opts.withUser && file.userId) ? hint?.packedUser ?? this.userEntityService.pack(file.userId) : null,
});
}
@@ -258,7 +261,10 @@ export class DriveFileEntityService {
files: MiDriveFile[],
options?: PackOptions,
): Promise<Packed<'DriveFile'>[]> {
const items = await Promise.all(files.map(f => this.packNullable(f, options)));
const _user = files.map(({ user, userId }) => user ?? userId).filter(isNotNull);
const _userMap = await this.userEntityService.packMany(_user)
.then(users => new Map(users.map(user => [user.id, user])));
const items = await Promise.all(files.map(f => this.packNullable(f, options, f.userId ? { packedUser: _userMap.get(f.userId) } : {})));
return items.filter(isNotNull);
}