diff --git a/backend/src/routes/albums/photos.js b/backend/src/routes/albums/photos.js index 7384b3b..a068d8f 100644 --- a/backend/src/routes/albums/photos.js +++ b/backend/src/routes/albums/photos.js @@ -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] + ); } } diff --git a/backend/src/services/album.js b/backend/src/services/album.js index 3ff87d6..c59396c 100644 --- a/backend/src/services/album.js +++ b/backend/src/services/album.js @@ -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'; diff --git a/docs/refactoring.md b/docs/refactoring.md index 887adc7..5d564d7 100644 --- a/docs/refactoring.md +++ b/docs/refactoring.md @@ -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단계 | 로거 통일 | 대기 |