집계 배치의 메모리가 3기가바이트를 넘어 태스크 한계에 가까웠다. 원인 중 하나가 두 컬럼을 문자열로 이어 만든 결합키 컬럼이었다.
Table of contents
상속되는 무게
결합키를 만들어 두면 한 컬럼으로 그룹핑할 수 있어 코드가 짧아진다. 문제는 그 컬럼이 137만 행짜리 프레임에 붙어 있고 문자열이라 무겁다는 점이었다.
거기서 파생된 슬라이스 셋이 그 컬럼을 그대로 상속하고 있었다. 하나를 지우면 넷이 줄어들므로 상속 관계를 보고 파급이 큰 것부터 골랐다.
바뀐 반환 형태
한 컬럼 그룹핑을 두 컬럼 그룹핑으로 바꿨는데 결과는 같아야 하지만 반환 형태가 달랐다. 최댓값 위치를 구하는 함수가 원래는 위치 인덱스를 주다가 다중 인덱스에서는 튜플을 돌려줬다.
그래서 필요한 성분만 꺼내는 처리를 추가했다. 그룹 축이 바뀌면 반환 형태가 바뀌고 그것을 안 보면 조용히 틀린 값이 흘러간다.
동점 처리의 확인
또 하나 확인할 것이 최댓값이 여럿일 때의 선택이었다. 그 함수는 첫 번째를 고르는데 어느 것이 첫 번째인지는 정렬 순서에 달렸다.
결합키가 두 컬럼을 이어 만든 것이므로 한 그룹 안에서는 양쪽 다 같은 순서가 되어 동작이 같다고 판단했다. 다만 이것은 추론이고 정렬을 전부 확인한 것이 아니라 3만 개 키 중 하나라도 다르면 검사기가 잡는다고 적고 진행했으며 검사는 통과했다.
이득만은 아닌 변경
메모리는 줄었지만 공짜가 아니었다. 그룹핑은 내부적으로 키를 정수로 바꾸는데 두 컬럼이면 두 번 하고 그룹핑이 여러 번 나오면 매번 다시 한다.
즉 CPU가 늘어난다. 그래서 메모리만 보지 않고 소요 시간도 함께 재면서 결합키를 하나씩 제거할 때마다 단계별로 기록했다. 한꺼번에 바꾸면 어느 것이 얼마나 줄였는지 알 수 없다.
맥락이 정한 방향
CPU가 늘고 메모리가 주는 교환에서 어느 쪽이 나은지는 이 배치의 맥락이 정했다. 하루 한 번 10분쯤 도는 배치이고 태스크 메모리 한계에 근접한 상태였다.
수 초가 늘어나는 것은 아무 문제가 아니지만 1기가바이트를 줄이는 것은 한계를 넘느냐 마느냐를 가르므로 의도한 방향의 교환이었다. 초당 수백 번 도는 API였으면 같은 변경이 반대 결론이 되므로 결합키를 없애는 것이 좋다는 일반 규칙은 없다.
정리
- 결합키는 코드를 짧게 하지만 메모리를 쓴다
- 파생 슬라이스가 상속하므로 하나 지우면 여럿이 준다
- 파급이 큰 것부터 고른다
- 그룹 축이 바뀌면 반환 형태가 바뀐다
- 동점 처리가 같은지 정렬 순서로 따로 확인한다
- 추론은 추론으로 두되 잡을 장치가 있으면 진행한다
- 결합키 제거는 CPU와 메모리의 교환이다
- 어느 쪽이 결정적인지는 맥락이 정한다