๐ก Issue
- ๊ธฐ์กด์๋ ๊ฐ๊ฐ์ ๋ฐ์ดํฐ ์ค 30์ผ์ด ์ง๋ ๋ฐ์ดํฐ๋ฅผ dirty checking ํ์ฌ status๋ฅผ updateํ์
<update id="updateOutOfDateSchedule"> UPDATE "Sbom_History" SET status = 'exp' WHERE DATE(created_at) < CURRENT_DATE - INTERVAL '30 days'; </update>
- ์ค์ ๋ก ๋จ๊ฑด์ dirty checking์ด์์ผ๋ฏ๋ก DB์ ๋ฐ์ํ๋ ๋งค ๊ฑด๋ง๋ค ์ปค๋ฅ์ ์ ๊ฐ์ ธ์ค๊ณ , Commit์ ํ๋ ๊ณผ์ ์์ ๋น์ฉ์ด ๋ฐ์ํ์ฌ ์ฑ๋ฅ์ ์ผ๋ก ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๊ฒ์ด ์ฐ๋ ค๋๋ค.
- ์์ผ๋ก ๋ง์ ์์ sbom ๋ฐ๊ธ๋ณธ์ด ์ ์ฅ๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ๊ฐ์ ์ด ํ์ํ๋ค.
๐ก MyBatis์์ Bulk ์ฐ์ฐ
- ๊ธฐ์กด์ ์ฌ์ฉํ๋ JPA๊ฐ ์๋, MyBatis์์ Bulk ์ฐ์ฐ์ ์๋ํ๋ค.foreach ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฆฌ์คํธ๋ ๋ฐฐ์ด์ ๊ฐ ์์ดํ
์ ๋ํ ์
๋ฐ์ดํธ ์ฟผ๋ฆฌ๋ฅผ ๋์ ์ผ๋ก ์์ฑ
- foreach ํ๊ทธ
- ์ ๋ฌ๋ฐ์ collection ์ธ์ ๊ฐ์ ๋ฐํ์ผ๋ก ๋ฐ๋ณต์ ์ธ SQL ๊ตฌ๋ฌธ์ ์์ฑ
- collection : ์ ๋ฌ๋ฐ์ ์ธ์๋ฅผ ์์ฑ ๊ฐ์ผ๋ก ์ฝ์ (ex. Map, Array, List, Set ๋ฑ)
- item : collection ์์ฑ์์ ์ ๋ฌ๋ฐ์ collection์ ์ธ์๊ฐ์ ๋์ฒดํ ‘์ด๋ฆ’์ ์ฝ์
- open & close : ๊ตฌ๋ฌธ์ด ์์/์ข ๋ฃ ๋ ๋ ์ฝ์ ํ ๋ฌธ์์ด
- separator : ๋ฐ๋ณต๋๋ ๊ตฌ๋ฌธ ์ฌ์ด์ ์ฝ์ ํ ๋ฌธ์์ด
- index : index๊ฐ์ ๋ถ๋ฅผ ๋ณ์๋ช ์ ์์ฑ๊ฐ์ผ๋ก ์ฝ์
- ์ ๋ฌ๋ฐ์ collection ์ธ์ ๊ฐ์ ๋ฐํ์ผ๋ก ๋ฐ๋ณต์ ์ธ SQL ๊ตฌ๋ฌธ์ ์์ฑ
- foreach ํ๊ทธ
- @Transactional ์ ํ์ฉํด์ bulk update ์์ ์ ํ๋์ ํธ๋์ญ์ ์ผ๋ก ๊ด๋ฆฌํจ์ผ๋ก์จ, ๋ชจ๋ ์ ๋ฐ์ดํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์ํ๋๊ฑฐ๋, ํ๋๋ผ๋ ์คํจํ ๊ฒฝ์ฐ ์ ์ฒด๊ฐ ๋กค๋ฐฑ๋์ด ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๋๋ก ๋ณ๊ฒฝํ๋ค.
- ์ต์ข ๋ณ๊ฒฝ ์ฝ๋
@Transactional
@Scheduled(cron = SCHEDULE)
public void sbomOutOfDateScheduling() {
List<sbomHistoryUpdateResponse> sbomHistoryUpdateList = sbomMapper.getSbomHistoryUpdateList();
if(!sbomHistoryUpdateList.isEmpty()) {
sbomMapper.updateOutOfDateSchedule(sbomHistoryUpdateList);
}
}
<select id="getSbomHistoryUpdateList" resultType = "com.sga.sbomProject.domain.sbom.dto.sbomHistoryUpdateResponse">
<![CDATA[
SELECT id
FROM "Sbom_History"
WHERE created_at::date < CURRENT_DATE - INTERVAL '30 days'
]]>
</select>
<update id="updateOutOfDateSchedule" parameterType="list">
<![CDATA[
UPDATE "Sbom_History"
SET status = 'exp'
WHERE id IN
<foreach collection="sbomHistoryUpdateList" item="item" open="(" separator="," close=")">
#{item}
</foreach>
]]>
</update>
- SELECT๋ก, ์ค๋ ๊ธฐ์ค 30์ผ ์ด์ ์ธ ๋ฐ์ดํฐ๋ฅผ ๋จผ์ ์ถ์ถ
- ํด๋น ์์ดํ ์ด ์กด์ฌํ ๊ฒฝ์ฐ, UPDATE๋ฅผ ์งํํ๋๋ฐ, ์ด๋ foreach ๊ตฌ๋ฌธ์ผ๋ก ํ๋ฒ์ UPDATE๋ฅผ ์งํ
๐ก Quality Test
- FK ์๋ฐ์ ๊ธํ๊ธฐ ์ํด, ๋จผ์ Scan_Target_Info์ ๋ฐ์ดํฐ 10๋ง๊ฐ ์ ์ฅ
DO $$
BEGIN
FOR i IN 1..1000000 LOOP
INSERT INTO "Scan_Target_Info" (target_type, target_uploaded_at)
VALUES('Solution', '2024-08-05 11:21:02.206909');
END LOOP;
END $$;
- ์ดํ, Sbom_History์ ์ฝ 10๋ง๊ฐ์ ๋ฐ์ดํฐ ์ฃผ์ (30์ผ ์ด์ ์ผ๋ก ์ฃผ์ ํ๋ค.)
DO $$
BEGIN
FOR i IN 1..100000 LOOP
INSERT INTO "Sbom_History" (scan_target_id, request_user_name, description, type, status, name, path, created_at, finished_at, created_by )
VALUES (i+2, 'test', 'test', 'SPDX','ava','test_name', 'test_path', NOW() - (INTERVAL '1 day' * (30 + i)),NOW() - (INTERVAL '1 day' * (30 + i)), 1 );
END LOOP;
END $$;
๐จ ํ ์คํธ ๋์ค ๋ฐ๊ฒฌํ ๋ฌธ์ ๐จ
PreparedStatement can have at most 65,535 parameters. Please consider using arrays, or splitting the query in several ones, or using COPY. Given query has 100,000 parameters
- ๋ด๊ฐ ์ฌ์ฉํ๋ postgreSQL์ ํ ์ฟผ๋ฆฌ์์ ์ต๋ 65,535๊ฐ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ง์ํ๋ค...
- ์ด ์ ํ์ PostgreSQL์ ๋ด๋ถ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๊ด๋ จ์์ผ๋ฏ๋ก ๋น์ฅ ๋ณ๊ฒฝ์ ์ด๋ ค์ธ ๊ฒ ๊ฐ์๋ค.
- 10000๊ฐ์ฉ 10๋ฒ ํ ์คํธ ํ๋ ๊ฑธ๋ก ์๋น์ค ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ๋ค
if(!sbomHistoryUpdateList.isEmpty()) {
int batchSize = 10000; // ํ ๋ฒ์ ์ฒ๋ฆฌํ ID์ ๊ฐ์
for (int i = 0; i < sbomHistoryUpdateList.size(); i += batchSize) {
int end = Math.min(sbomHistoryUpdateList.size(), i + batchSize);
List<Long> batchList = sbomHistoryUpdateList.subList(i, end);
System.out.println("update ์ฟผ๋ฆฌ ์์ : " + System.currentTimeMillis());
sbomMapper.updateOutOfDateSchedule(batchList);
System.out.println("update ์ฟผ๋ฆฌ ๋ : " + System.currentTimeMillis());
}
}
๐ Result
- select ์๊ฐ : 575ms (0.5์ด)
- update ์๊ฐ : 10000๊ฐ์ฉ :
- 0๋ฒ์งธ: 289 ms
- 10000๋ฒ์งธ: 619 ms
- 20000๋ฒ์งธ: 235 ms
- 30000๋ฒ์งธ: 202 ms
- 40000๋ฒ์งธ: 207 ms
- 50000๋ฒ์งธ: 172 ms
- 60000๋ฒ์งธ: 189 ms
- 70000๋ฒ์งธ: 172 ms
- 80000๋ฒ์งธ: 216 ms
- 90000๋ฒ์งธ: 168 ms
- ⇒ ํ๊ท : 244.9 ms
- ๊ฒฐ๊ณผ์ ์ผ๋ก 10๋ง๊ฐ์ ๋ฐ์ดํฐ 3์ด update
'BACKEND > JAVA & SPRING' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
@SpringBootTest, @MockBean, Mockito, Junit ๋ฑ ํ ์คํธ์ ๋ํด์โฆ (1) | 2024.12.15 |
---|---|
์ ์บ์คํ , ๋ค์ด์บ์คํ ์ ๋ํด (3) | 2024.10.30 |
MultipartFile์ Ajax๋ฅผ ํ์ฉํ ํ์ผ ์ ๋ก๋ (0) | 2024.08.01 |
Transaction์ ์ ํ (feat. REQUIRES_NEW์ ๋ฌธ์ ์ ) (0) | 2024.07.31 |
[Spring Security + JWT + OAUTH2] ์นด์นด์ค/๋ค์ด๋ฒ ์ธ๋ถ ๋ก๊ทธ์ธ ๊ตฌํ (0) | 2024.04.30 |