엑셀 다운로드가 천여 건에 60초를 넘겼고 메모리 때문에 청크로 나눠 처리하고 있었다. 쿼리 수부터 세어 보니 청크로 나눴을 때가 한 번에 가져올 때보다 다섯 배 많았다.
Table of contents
Open Table of contents
청크마다 반복된 로딩
모델에 자동 즉시 로딩이 걸려 있어서 조회할 때마다 여러 관계를 같이 가져오고 있었다. 한 번에 가져오면 그 로딩이 한 번만 돌지만 청크로 나누면 청크 횟수만큼 반복된다.
메모리를 줄이려고 나눈 것이 쿼리를 배수로 늘린 셈이었다. 자동 로딩이 걸린 모델을 청크로 처리할 때 이 교환이 생기므로 나누기 전에 로딩 목록부터 확인해야 한다.
안 쓰는 관계들
자동 로딩 목록과 내보내기 코드가 실제로 참조하는 관계를 대조했다. 셋이 가져오기만 하고 안 쓰이고 있었다.
자동 로딩을 끄는 전용 메서드가 이 버전에는 없어서 다른 방법을 찾았다. 로딩 목록을 빈 배열로 대체한 뒤 필요한 것만 명시하는 방식이었다.
소스가 정한 호출 순서
이 호출에 함정이 있어서 프레임워크 소스를 열어 봤다. 그 메서드가 배열을 병합하는 것이 아니라 대체하고 있었다.
그러면 목록을 비우는 호출이 먼저 오고 필요한 것을 명시하는 호출이 뒤에 와야 한다. 순서를 반대로 쓰면 명시한 것까지 사라지므로 소스를 안 봤으면 순서를 반대로 썼을 것이고 그 실수는 조용히 지나간다.
반복된 개수 조회
또 하나 찾은 것이 조건 검사마다 개수를 부르고 있는 코드였다. 같은 개수 쿼리가 검사 횟수만큼 실행되고 있었다.
한 번 구해 변수에 담고 그것을 쓰게 고쳤다. 이런 것은 눈에 잘 안 띄는데 각 줄만 보면 자연스러운 코드이기 때문이다.
셋을 조합한 결과
개수 캐싱과 로딩 차단과 청크 크기 확대 셋을 같이 적용해 쿼리 수를 3분의 1로 줄였다. 청크 크기를 키운 것도 효과가 있었는데 관계 로딩이 청크마다 도므로 횟수가 줄면 쿼리도 준다.
다만 그것은 메모리와의 교환이라 이 데이터에서 감당 가능한 크기로 정했다. 이 작업에서 결정적이었던 것은 문서에 안 나온 동작을 프레임워크 소스에서 확인한 것이었다.
정리
- 자동 즉시 로딩이 청크마다 반복돼 쿼리가 배수로 는다
- 자동 로딩 목록과 실제 사용 관계를 대조하면 미사용이 나온다
- 배제 메서드가 없으면 목록을 비우고 필요한 것만 명시한다
- 그 메서드가 대체인지 병합인지 확인한다
- 순서가 반대면 명시한 것까지 사라진다
- 개수 조회를 반복 호출하면 그만큼 실행되므로 한 번 구해 담는다
- 청크 크기를 키우면 로딩 반복이 주는 대신 메모리를 더 쓴다
- 동작이 애매하면 프레임워크 소스를 읽는다