재고가 없는 상품을 판매중지시키는 배치를 SQL로 옮기는 작업을 하면서 기존 코드를 봤다. 재고가 정확히 0과 같은지를 비교하는 조건 하나가 거기 들어 있었다.
Table of contents
Open Table of contents
세어서 확인한 실재
그 조건을 그대로 옮기려던 참에 0 이하도 있지 않느냐는 물음이 왔다. 추측으로 답하지 않고 운영 데이터베이스에서 직접 세어 보기로 했다.
상품 테이블에 승인되고 정상 상태인데 재고가 음수인 것이 열일곱 건 있었고 가장 작은 값이 음의 한 자리였다. 옵션별 재고 테이블은 275건이나 됐고 가장 작은 값이 네 자리 음수였다.
영원히 안 잡히는 상품
그 열일곱 건은 승인되고 정상 상태이므로 지금 판매 중인 상품들이었다. 재고가 음수인 상품이 그대로 마켓에 걸려 있는 상태였다.
기존 조건은 정확히 0인지만 보므로 음수인 값은 아예 걸리지 않는다. 배치가 매일 돌아도 그 상품들은 영원히 중지되지 않으므로 조건을 0 이하로 바꿔야 했다.
같은 조건을 쓰는 모든 곳
이것은 이 배치만의 문제가 아니라 재고를 기준으로 상품을 거르는 모든 곳에 해당하는 얘기다. 판매중지 배치와 품절 표시와 재고 통계와 검증 쿼리가 전부 같은 조건을 쓰고 있었다.
같음 비교를 쓰는 곳을 전부 찾아 이하 비교로 바꿔야 하는 작업이 된다. 한 곳만 고치고 끝내면 나머지에서 같은 누락이 계속 생기기 때문이다.
합계가 왜곡하는 실체
옵션이 있는 상품은 재고가 옵션별 합계인데 여기서는 음수가 더 위험했다. 한 옵션의 큰 음수가 다른 옵션의 양수를 상쇄하면 팔 수 있는 옵션이 있는데도 상품 전체가 재고 없음으로 잡힌다.
반대 경우도 가능한데 큰 양수가 작은 음수를 덮으면 못 파는 옵션이 있는데도 합계로는 재고가 있어 보인다. 합계가 실체를 양방향으로 왜곡하므로 합계만 보고 판정하면 안 된다.
안 판 원인과 조회 방식
음수 재고가 애초에 왜 생기는지는 이번에 보지 않았는데 차감이 중복으로 돌거나 동시 주문에서 잠금 없이 빼는 것으로 짐작만 했다. 이번 작업 범위가 아니라 재고 차감 경로의 별건 조사 대상으로 남긴다고 적었다.
이 확인은 운영 데이터베이스를 대상으로 하므로 행을 안 읽고 집계만 각 테이블에 한 번씩 냈다. 이 조사의 시작이 0 이하도 있지 않느냐는 물음이었는데 안 물었으면 기존 조건을 그대로 옮겼을 것이고 기존 코드를 옮기는 작업이 그 조건을 검증할 기회이기도 하다.
정리
- 음수 재고가 실재하므로 추측하지 말고 세어 본다
- 0과 같은지로 판정하면 그 상품들을 전부 놓친다
- 조건은 0 이하여야 한다
- 재고로 거르는 모든 배치와 통계와 검증에 같이 적용한다
- 합계는 음수가 양수를 상쇄해 실체를 왜곡한다
- 반대로 양수가 음수를 덮어 있어 보이게도 한다
- 원인을 안 팠으면 별건 조사 대상으로 분리해 적는다
- 옮기는 작업이 기존 조건을 검증할 기회다