๊ฐ์
์ฌ๋ด์ ๋ ๊ฑฐ์ ์ด๋๋ฏผ ์์คํ ์์ ์๊พธ ํน์ ์๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ ์ ์จ์ด ์น์๋ค๊ฐ ๊ฒฐ๊ตญ ๋ฉ์ถ๋ ์ด์๊ฐ ์์๋ค.
์์ธ์ ๋ถ์ํด๋ณธ ๊ฒฐ๊ณผ ์ถ๋ ฅ ๊ฑด์๊ฐ ๋ง์ ๋ฉ๋ด์์ ์์
๋ค์ด๋ก๋ ์์ฒญ์ ์ ์ฒด ์กฐํ
-> List ํํ๋ก ๋ฉ๋ชจ๋ฆฌ ์ ์ฅ
-> ์์
์์ฑ
-> ๋ค์ด๋ก๋
๊ณต์ ์ผ๋ก ํ์ผ์ ๋ด๋ ค์คฌ๋๋ฐ,
๋ฐ์ดํฐ๊ฐ ์ ์๋ค๋ฉด ์๊ด์์ง๋ง ํด๋น ๋ฉ๋ด๋ ๊ธฐ๊ฐ์ ์กฐ๊ธ๋ง ๋๋ ค๋ ์์ญ๋ง ๊ฑด์์ 100๋ง๊ฑด ๊น์ง ๋์ด๋ ์ ์๋ ๋ฉ๋ด์๊ธฐ ๋๋ฌธ์ ๋น๋ฒํ๊ฒ ๋ฌธ์ ๊ฐ ๋์๋ค.
๊ฒฐ๊ตญ ๋์ฉ๋ ๋ค์ด๋ก๋๋ฅผ ์ํ ๊ณต์ ์ด ์ถ๊ฐ๋ก ํ์ํด์ก๋๋ฐ ํด๋น ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๋ฉฐ ์์๋ ๊ณผ์ ๋ค์ ๋ช๊ฐ์ง ๊ธฐ๋กํด๋ณผ๊น ํ๋ค.
์์ธ ์ฐพ๊ธฐ
๊ฐ์์ ์์ฑํ์ง๋ง, ๊ธฐ์กด์ ์์ ๋ค์ด๋ก๋ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ๋ฐ์ดํฐ ์ ์ฒด ์กฐํ ์์ฒญ
- JDBC ๋ก ๋ถํฐ ์๋ต๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ํ๋์ List ์ ์ผ๊ด ์ ์ฅ
- Apache Poi ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ์ฌ ์ผ๊ด ์์ File ์์ฑ
- ์์ ์์ฑํ ํ์ผ์ response ๋ก ์๋ต ์ฒ๋ฆฌ
์์ธํ ์ง๋จ์ ํ๊ธฐ ์ ์๋ ๋๋์ ๋ฐ์ดํฐ๋ฅผ XSSF ํด๋์ค๋ฅผ ์ด์ฉํ์ฌ ์์ ์ ๋ง๋ค๋ ๋์ค OOM(Out of Memory Error) ๋ก ์ธํ ์ฅ์ ๊ฐ ๋ฐ์ํ์ ๊ฒ์ด๋ผ ์ถ์ธกํ๋ค.
ํ์ง๋ง ์ค์ ๋ก ์ฝ๋๋ฅผ ๋ณด๋ํ๊ฐ์ง ์๋ฌธ์ด ๋ค์๋ ๊ฒ์ด 100๋ง๊ฑด์ ๋ฐ์ดํฐ๋ฅผ List ์๋ฃํ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ๋ก ์ฌ๋ฆฌ๋๋ฐ ์ด ์์ ์๋ ์ฅ์ ๊ฐ ๋์ง ์๋์ง๊ฐ ์๋ฌธ์ด์๋ค.
๋ง์ฝ ์๋ฌธ์ด ๋ง์๋ค๋ฉด ์ค์ ์ฅ์ ๊ฐ ๋ฐ์ํ ์์ ์ 3๋ฒ์ด ์๋๊ณ 2๋ฒ ์์ ์ผ ๊ฒ์ด์๋ค.
์ฌ์ค 2๋ฒ์ด๋ 3๋ฒ์ด๋ ์ด๋ฏธ ์์ ํด์ผ ํ ๋ฐฉํฅ์ ๋์ถฉ ๊ฐ์ด ์กํ์ง๋ง, ์ด์ ๋ถํฐ ๋ผ์ด๋ธ ์๋น์ค์ ์๋ชป๋ ์ฝ๋๋ก ์ธํด ๋ฐ์ํ OOM์ ๋ฉ์ง๊ฒ ํด๊ฒฐํ๋ ํ์(?)์ด ์์๊ธฐ ๋๋ฌธ์ ์กฐ๊ธ ๋ ์ ํํ๊ฒ ์์ธ์ ์ง๋จํด๋ณด๊ณ ์ถ์๋ค.
๋ฐ๋ผ์ ํด๋น ์ด์๋ฅผ ์กฐ๊ธ ๋ ์ ๋ฐํ๊ฒ ๋ถ์ํด๋ณด๊ธฐ ์ํด ์ฌํ์ ํด๋ณด์๋ค.
๋ก์ปฌ์์ ๊ตฌ๋ํ๋๋ผ๋ ์ค์ ์๋ฒ์ Heap ๊ณต๊ฐ ํฌ๊ธฐ์ ์ฐจ์ด๊ฐ ์์ ๊ฒ์ด๋ฏ๋ก ์ฐ์ VM Option ์ผ๋ก ๊ฐ์ ๊ณต๊ฐ์ ํ ๋นํด ์ฃผ์๋ค.
๊ทธ ํ OutOfMemory ์ HeapDump ํ์ผ์ ๋จ๊ธฐ๋๋ก ์ต์ ์ ์ถ๊ฐํ๋ค.
-Xms:1024m
-Xmx:2048m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump/directory
๊ทธ๋ฆฌ๊ณ ๋ฌธ์ ๋ก ์ถ์ ๋๋ ์์ ๊ธฐ๋ฅ์ ์คํํ์ฌ ๊ฒฝ๊ณผ๋ฅผ ์ง์ผ๋ณด์๋๋ ์ค์ ๋ก ๋ค์๊ณผ ๊ฐ์ ์์ธ๋ฉ์์ง๊ฐ ๋ฐ์ํ์๋ค.
๋คํํ ์์๋๋ก OOM ์ด ๋ฐ์ํ์์ผ๋ฏ๋ก ๋ฐฉ๊ธ ์ค ์ต์
์ผ๋ก ์ธํด HeapDump ํ์ผ์ด ์์ฑ ๋์๊ณ ,
์ข ์ ์ง์ ํ ๊ฒฝ๋ก์ ์๊ธด hprof ํ์ฅ์์ heap dump ํ์ผ์ Eclipse Memory Analizer ๋ฅผ ์ด์ฉํ์ฌ ๋ถ์ํ๋ค.
(heapdump ๋ถ์ ๋ฐฉ๋ฒ์ ๋ํด ์ฐธ์กฐํ ๋งํฌ: https://jupiny.com/2019/07/15/java-heap-dump-analysis/)
๋ถ์ ๊ฒฐ๊ณผ Heap ์ ์ ๋ iBtais ํจํค์ง ๋ด DefaultResultHandler
์์ ์ปฌ๋ ์
๊ฐ์ฒด๋ค๋ก ์ธํด ๋ฐ์ํ๊ณ ํด๋น ํด๋์ค๊ฐ ์๋ํ๋ ๋ฐฉ์์ ํ์ธํด๋ณด๋ ๋ค์๊ณผ ๊ฐ์๋ค.
ํด๋น API ๋ resultSet ์์ ํ ์ค์ฉ ์กฐํ ๊ฒฐ๊ณผ๋ฅผ List ์ ๋๊น์ง add ํ๋ ๊ตฌ์กฐ์๋ค.
์์๋๋ก repository layer ์์ ์ต์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ ํ์ด์ง๋ ์์ด ๋ฉ๋ชจ๋ฆฌ์ ์๋ ์์ ๋ถํฐ ์ด๋ฏธ GC ๋ฅผ ๋ง๋น์ํฌ ์ ๋์ ๋ฉ๋ชจ๋ฆฌ ์ ์ ๊ฐ ๋ฐ์ํ๊ณ ์ด๋ฅผ ์์ ํ๊ธฐ ์ํ ์์
์ด ์งํ๋์๋ค.
CustomResultHandler ์ ์
Mybatis ์์๋ ๋ฐ์ดํฐ ์กฐํ ์ ResultHandler
์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ๋ ์ปค์คํ
ResultHandler ๊ฐ์ฒด๋ฅผ ์ ์ํ ์ ์๋ค.
์์ DefaultResultHandler
๊ฐ์ฒด๊ฐ ๋จ์ํ๊ฒ ์กฐํ ๊ฒฐ๊ณผ๋ฅผ ํ ์ค์ฉ List์ Add ํด์ฃผ๋ ๊ตฌ์กฐ๋ผ๋ฉด, ์์๋ก ๋ง๋ ResultHandler ๊ฐ์ฒด์์ ํ ์ค์ฉ Excel ๋ฐ์ดํฐ๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋ ์ผ์ด์๋ค.
ํ์ง๋ง ๊ธฐ์กด๋๋ก XSSF ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด ์กฐํํ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์์ ๋ก ๋ด๋ณด๋ผ ๋ ๊น์ง ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ ํ๋ฏ๋ก ์์ List ์ ์ ์ฅํ๋ ๋ฐฉ์๊ณผ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋ค.
๋ฐ๋ผ์ SXSSF ์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํด์ผ ์ค๊ฐ์ค๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ์ ๋ณด๋ฅผ ํ์ผ๋ก flush ํด์ฃผ๊ณ ๋น์ฐ๋ ๋์์ด ์ด๋ฃจ์ด์ง๊ธฐ ๋๋ฌธ์ ์์ ์ ์ผ๋ก ๋์ํ ์ ์๋ค.
์์ ๋งํ๋๋ก ๊ตฌํํ๋ค๋ฉด CustomResultHandler
๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋ ์ ์๋ค.
@Slf4j
public class MyCustomResultHandler implements ResultHandler {
private final Workbook workbook;
private Sheet sheet;
private rowIndex = 3;
public MyCustomResultHandler(Workbook workbook) {
this.workbook = workbook;
createSheet();
}
private void createSheet() {
sheet = workbook.createSheet("Sheet Name");
//Set Styles ...
//Create Title ROW ...
//Create Header ROW ...
}
@Override
public void handleResult(ResultContext resultContext) {
Map<String, Object> result = (Map<String, Object>) resultContext.getResultObject();
Row row = sheet.createRow(rowIndex++);
//๊ธฐ๋กํ๋ ๋ก์ง
}
}
์์์ ๋ง๋ MyCustomResultHandler
๊ฐ์ฒด๋ Mybatis ์ ๋ค์ ์ธํฐํ์ด์ค๋ฅผ ์ด์ฉํ๋ฉด ๋๋ค.
๊ทธ๋ฆฌ๊ณ ํด๋น ResultHandler ๋ฅผ ํธ์ถํ๋ ServiceLayer ์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ฐธ์กฐํ SXSSF Workbook ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํด์ ๋๊ฒจ์ฃผ๋ฉด ๋๋ค.
public void createExcel() {
SXSSFWorkbook workbook = new SXSSFWorkbook(10000); //flsuh ํด์ค row ๊ฐ์๋ฅผ ์ง์ ํ๋ค.
MyCustomResultHandler handler = new MyCustomResultHandler(workbook, resultCount);
sqlsession.select("statement", params, handler);
//write and dispose Excel File
}
๋จ์ ๊ณผ์
์ฌ์ค ๊ธฐ์กด ์ฌ์ง ์ธ์๋ค์ ๋๋ฅด๋ฉด ์๋น์ค๊ฐ ์ฃฝ์ฌ๋ฒ๋ฆฌ๊ณ ๋ง๋ ์น๋ช ์ ์ธ ์คํ๋๋ฌธ์ ์ฌ์ฉํ ์๊ฐ๋ ์ํ์ง๋ง, ์ ๊ท ์ ์ฌ์๋ค๋ง ํ๋ฒ์ฉ ๋๋ฌ๋ด์ ์ฌ๊ณ ๋ฅผ ์น๊ณ ์ผ ๋ง๋ ๊น์ง์์๊ฐ์(?) ๊ธฐ๋ฅ์ด๊ธฐ๋ ํ๋ ๊ฒ ๊ฐ๋ค.
๊ฐ๋ฐํ์์๋ ์ฌ์ฐจํ๋ฉด DB์์ ์ง์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํด์ ๋ณด๋ด์ฃผ๊ณ ๋ง์ง ๋ผ๋ ๋๋์ผ๋ก ๋จ์์๋ ์ผ์ผ๋ฌต์ ๊ณผ์ ์ด๊ธฐ๋ ํ์๋๋ฐ, ๋ง์ ๊ตฌํํ๊ณ ๋ณด๋ ๊ฐ์ ํด์ผ ํ ์ ์ด ๋ ๋ง์ด ๋ณด์ด๊ธด ํ๋ค.
- 100๋ง row ์ ๋๋ฅผ ์ฐ๊ฒ ๋๋ฉด ์ผ๋จ ํ์ผ์ ๋ง๋๋๋ฐ ๋๋ฌด ์ค๋์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค.
- ๊ธฐ์กด์ ๋๊ธฐ์ ์ฒ๋ฆฌ๋ฅผ ๊ทธ๋๋ก ๋์ด์, ์ฌ์ฉ์๋ ๊ฒฐ๊ตญ ์ต๋ 20๋ถ๊น์ง ๋ค์ด๋ก๋ ์ค ํ๋ฉด๋ง ํ์ผ์์ด ๊ธฐ๋ค๋ฆฌ๊ณ ์์ด์ผ ํ๋ค.
์ฐ์ ์ฒซ ๋ฒ์งธ ๋ฌธ์ ์ธ ํ์ผ ์์ฑ ์๊ฐ์ ์ค์ด๊ธฐ ์ํด์ ํ ์ ์๋๊ฒ์ด ๋ฌด์์ด ์์๊น ๊ณ ๋ฏผํด๋ณธ ๊ฒฐ๊ณผ, JDBC ์กฐํ ์ resultSet ์ ๋ฒํผ๋ฅผ ๋๋ฆฌ๋ ๋ฐฉ๋ฒ์ด ์์ง ์์๊น ์๊ฐํด๋ณด์๋ค.
ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์์๋ 10000 row ๊น์ง ์์
์ปดํฌ๋ํธ๋ฅผ ๋ค๊ณ ์๋ค๊ฐ flush ํ๋๋ฐ, resultSet ์ ํฌ๊ธฐ๋ 10000์ผ๋ก ๋ง์ถ์ด์ฃผ๋ฉด ์์ฑ์๋๊ฐ ์ค์ด๋ค ๊ฒ์ด๋ผ ์์ํ๋ค.
<select id="queryName" parameterType="hashMap" fetchSize="10000">
<!--query-->
</select>
๋ค์๊ณผ ๊ฐ์ด fetchSize ์ค์ ์ 10000 ์ผ๋ก ์์ ํ๋ฉด ๋๋ค. (default ๊ฐ์ 10์ด์๋ค.)
์๋๋ ๊ฐ fetchSize๋ณ ์คํ ๊ฒฐ๊ณผ์ด๋ค.
- fetch - 10
- ์์ ๋ค์ด๋ก๋ ๊ฑด์ : 154325๊ฑด
- ์์ ๋ค์ด๋ก๋ ์์์๊ฐ : 326099millis
- fetch - 200
- ์์ ๋ค์ด๋ก๋ ๊ฑด์ : 153908๊ฑด
- ์์ ๋ค์ด๋ก๋ ์์์๊ฐ : 80020millis
- fetch - 10000
- ์์ ๋ค์ด๋ก๋ ๊ฑด์ : 154008๊ฑด
- ์์ ๋ค์ด๋ก๋ ์์์๊ฐ : 49050millis
fetch size ๋ฅผ ๋์ผ์๋ก ๋๋ผ๋งํฑํ ์ฑ๋ฅ ๊ฐ์ ์ด ๋๊ณ ์๋๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ์ง๋ง fetch size ๋ฅผ ๋๋ฌด ๋์ด๊ฒ ๋๋ฉด ๋ฉ๋ชจ๋ฆฌ์ ๋ถ๋ด์ด ๋๊ณ ์ด์ฐจํผ flush๊ฐ ์ด๋ฃจ์ด ์ง๋๋ง๋ค ์ค๋ฒํค๋๊ฐ ๊ฑธ๋ฆด ์ ์์ผ๋ ์ ์ ํ ์์น๋ฅผ ์ฐพ๋๊ฒ์ด ์ข์๋ฏ ํ๋ค.
๋ค์์ ๋๋ฒ์งธ ๋ฌธ์ ์ธ ์ฌ์ฉ์ ํ๋ฉด ๊ฐ์ ์ธ๋ฐ ์ฝ๊ฐ์ UI์ ์ธ ์์ด๋์ด๋ฅผ ๊ฐ๋ฏธํ๋ค๋ฉด ์๋ต๋ฐ์ popup ์ด๋ iframe ์ ์ ๊ณตํ์ฌ ํด๋น element ๋ก return ๋ฐ๋ ๊ฒ์ด ๊ฐ์ฅ ๊น๋ํ๊ฒ ๋ณด์ผ ๊ฒ์ผ๋ก ์์๋๋ค.
'๋ ธํธ > JAVA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JAVA] Thread ๊ธฐ์ด (0) | 2022.06.15 |
---|---|
[JAVA] ํท๊ฐ๋ฆฌ๋ ์์ ์ ๋ฆฌ (0) | 2022.05.11 |
[JAVA] clone() ๋ฉ์๋ ์ ๋ฆฌ (0) | 2022.04.20 |
[JAVA/๋ฒ์ญ] Static ๋ฉค๋ฒ๋ฅผ ์ํ JVM ์คํ ๋ฆฌ์ง (0) | 2022.04.12 |
[JAVA] String Literal ๊ณผ String Pool (0) | 2022.03.31 |