refactor(backend): 순차 쿼리 → 병렬 처리

- getAlbumDetails: tracks/teasers/photos 쿼리 Promise.all로 병렬 실행
- photos.js: 멤버 INSERT for loop → VALUES 배치 처리

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-01-21 14:12:27 +09:00
parent c3e504d1e3
commit 0a91d04992
3 changed files with 39 additions and 34 deletions

View file

@ -166,12 +166,11 @@ export default async function photosRoutes(fastify) {
photoId = result.insertId;
if (meta.members && meta.members.length > 0) {
for (const memberId of meta.members) {
await connection.query(
'INSERT INTO album_photo_members (photo_id, member_id) VALUES (?, ?)',
[photoId, memberId]
);
}
const values = meta.members.map(memberId => [photoId, memberId]);
await connection.query(
'INSERT INTO album_photo_members (photo_id, member_id) VALUES ?',
[values]
);
}
}

View file

@ -10,33 +10,35 @@
* @returns {object} 상세 정보가 포함된 앨범
*/
export async function getAlbumDetails(db, album) {
const [tracks] = await db.query(
'SELECT * FROM album_tracks WHERE album_id = ? ORDER BY track_number',
[album.id]
);
// 트랙, 티저, 포토 병렬 조회
const [[tracks], [teasers], [photos]] = await Promise.all([
db.query(
'SELECT * FROM album_tracks WHERE album_id = ? ORDER BY track_number',
[album.id]
),
db.query(
`SELECT original_url, medium_url, thumb_url, video_url, media_type
FROM album_teasers WHERE album_id = ? ORDER BY sort_order`,
[album.id]
),
db.query(
`SELECT
p.id, p.original_url, p.medium_url, p.thumb_url, p.photo_type, p.concept_name, p.sort_order,
p.width, p.height,
GROUP_CONCAT(m.name ORDER BY m.id SEPARATOR ', ') as members
FROM album_photos p
LEFT JOIN album_photo_members pm ON p.id = pm.photo_id
LEFT JOIN members m ON pm.member_id = m.id
WHERE p.album_id = ?
GROUP BY p.id
ORDER BY p.sort_order`,
[album.id]
),
]);
album.tracks = tracks;
const [teasers] = await db.query(
`SELECT original_url, medium_url, thumb_url, video_url, media_type
FROM album_teasers WHERE album_id = ? ORDER BY sort_order`,
[album.id]
);
album.teasers = teasers;
const [photos] = await db.query(
`SELECT
p.id, p.original_url, p.medium_url, p.thumb_url, p.photo_type, p.concept_name, p.sort_order,
p.width, p.height,
GROUP_CONCAT(m.name ORDER BY m.id SEPARATOR ', ') as members
FROM album_photos p
LEFT JOIN album_photo_members pm ON p.id = pm.photo_id
LEFT JOIN members m ON pm.member_id = m.id
WHERE p.album_id = ?
GROUP BY p.id
ORDER BY p.sort_order`,
[album.id]
);
const conceptPhotos = {};
for (const photo of photos) {
const concept = photo.concept_name || 'Default';

View file

@ -60,9 +60,13 @@
---
### 7단계: 순차 쿼리 → 병렬 처리
- [ ] `services/album.js` getAlbumDetails - tracks, teasers, photos 병렬 조회
- [ ] `routes/albums/photos.js` - 멤버 INSERT 배치 처리
### 7단계: 순차 쿼리 → 병렬 처리 ✅ 완료
- [x] `services/album.js` getAlbumDetails - tracks, teasers, photos 병렬 조회
- [x] `routes/albums/photos.js` - 멤버 INSERT 배치 처리
**수정된 파일:**
- `src/services/album.js` - Promise.all로 3개 쿼리 병렬 실행
- `src/routes/albums/photos.js` - for loop → VALUES ? 배치 INSERT
---
@ -107,7 +111,7 @@
| 4단계 | 에러 처리 통일 | ✅ 완료 |
| 5단계 | 중복 코드 제거 | ✅ 완료 |
| 6단계 | 매직 넘버 config 이동 | ✅ 완료 |
| 7단계 | 순차→병렬 쿼리 | 대기 |
| 7단계 | 순차→병렬 쿼리 | ✅ 완료 |
| 8단계 | meilisearch 카테고리 ID | 대기 |
| 9단계 | 응답 형식 통일 | 대기 |
| 10단계 | 로거 통일 | 대기 |