특정 유형의 이의신청이 처리됐는지를 확인해 달라는 요청을 받았다. 화면 이름은 알겠는데 그것이 어느 테이블에 쌓이는지를 몰랐다.
Table of contents
Open Table of contents
조사 — 이름 비슷한 테이블들
SHOW TABLES LIKE '%appeal%' 로 훑으니 비슷한 이름의 것이 여럿 나왔다. DESC 로 하나씩 열어 보고 requested_at 과 approved_at 과 rejected_at 이 있는 것을 골랐다.
나머지는 성격이 다른 별개 테이블이었고 이름이 비슷해 헷갈리기 쉬웠다. 고른 테이블의 status 를 GROUP BY 로 세어 보니 REQUESTED 와 APPROVED 와 REJECTED 셋이었다.
제약 — 자연어 사유의 한계
reason 컬럼을 보니 코드값이 아니라 사람이 쓴 자유 문장이었다. 그러면 특정 유형을 고를 때 LIKE 패턴으로만 걸 수 있고 정확도에 한계가 생긴다.
이 한계는 없앨 수 없으므로 그대로 안고 가되 알고 시작하는 것이 중요했다. 나중에 결과를 보고할 때도 그 정확도 한계를 함께 적어야 하기 때문이다.
판단 기준 — 규모를 확인한 전수 조회
조회 전에 SHOW INDEX 를 보니 기본키뿐이고 status 로도 created_at 으로도 인덱스가 없었다. 두 가지 방법이 있었는데 조회용 인덱스를 먼저 만드는 것과 규모를 확인하고 전수 스캔으로 가는 것이다. 뒤쪽을 골랐다. 이유는 한 번 볼 조회에 운영 표의 스키마를 바꾸는 것이 더 큰 일이라서다. 대신 조회가 수백만 건 규모였으면 이 선택을 되돌려야 하는 것을 감수했다.
전체가 3천 건대여서 전수 스캔을 걸어도 감당되는 규모였다. 규모를 확인하고 나서 전수 조회를 결정한 것이고 수백만 건이었으면 다른 방법을 찾아야 했다.
원인 — 레거시가 부풀린 미처리
기간 조건 없이 REQUESTED 를 세니 꽤 많았고 이것을 다 처리해야 하는지 싶었다. YEAR(created_at) 별로 나눠 보니 몇 해 전에 만들어진 것이 대부분이었다.
당시 처리 흐름이 지금과 달랐거나 이관 과정에서 상태가 안 옮겨진 것으로 보였다. 기간 조건 없이 세면 이런 레거시가 실제 잔여 업무량을 부풀린다.
요청받은 기간으로 좁히니 전체 십여 건에 대부분이 APPROVED 이고 나머지가 REJECTED 이며 REQUESTED 가 0건이었다. 전량 처리 완료이고 이후 신규 접수도 없었으므로 답이 명확해졌는데 기간 없이 셌으면 미처리가 수백 건이라는 답이 나왔을 것이다.
주의 — 문구 차이와 근본 제약
정리하는 중에 reject_reason 문구가 채널군에 따라 두 종류로 갈리는 것도 봤다. 한 문구로만 LIKE 검색하면 절반이 안 잡히므로 자연어 컬럼은 실제 값을 그룹핑해서 확인하고 가정하지 않아야 한다.
마지막으로 근본 제약을 적었다. 이관 과정에서 이전 상품의 중지와 품절 이력이 안 넘어와서 실제로 중지 이력이 있었는지를 조회로 확인할 수 없고 수동 확인이 필요하다. 로직 문제가 아니라 데이터가 없어서 못 하는 것이라 이번에 해결되지 않고 남는다고 그대로 적었다.
정리
- 화면 이름과 실체 테이블을 먼저 확정한다
- 이름 비슷한 테이블이 여럿일 수 있다
- 사유가 자연어면 패턴 매칭으로만 걸린다
SHOW INDEX에 없으면 규모를 확인하고 전수 조회 여부를 정한다- 기간 조건 없이 미처리를 세면 레거시가 업무량을 부풀린다
- 자연어 컬럼은 실제 값을
GROUP BY로 확인한다 - 테이블과 스키마와 인덱스와 실행 계획을 차례로 본다
- 데이터가 없어서 못 하는 것은 근본 제약으로 적는다