고객 문의로 들어온 주문 번호 하나를 찾아 달라는 요청을 전달받았다. 번호가 있으니 금방 찾을 것으로 봤는데 어느 테이블에서도 나오지 않았다.
Table of contents
Open Table of contents
배경 — 어디에도 안 나오던 주문 번호
orders.order_no 와 channel_orders.channel_order_no 와 관련 테이블들을 차례로 조회했지만 전부 결과가 없었다. 조회 대상과 조건을 바꿔 가며 여러 번 확인해 봐도 결과는 마찬가지였다.
이 시점에서 해당 주문은 존재하지 않는다고 답하고 끝낼 수도 있는 상황이었다. 다만 그 답이 성립하려면 내가 조회한 범위가 데이터 전체와 같아야 했다.
검증 — 인덱스를 보고 조회한 이유
조회할 때마다 SHOW INDEX 로 그 컬럼에 인덱스가 걸려 있는지를 먼저 확인하고 들어갔다. channel_order_no 는 인덱스가 없어서 단독 조건으로 걸면 테이블 전체를 훑는다.
EXPLAIN 의 rows 가 백만 단위였고 그 값이 추정치여도 자릿수만으로 판단은 충분했다. 두 가지 방법이 있었는데 운영에서 그대로 전체 스캔을 돌리는 것과 created_at 인덱스 조건을 함께 거는 것이다. 뒤쪽을 골랐다. 이유는 운영 데이터베이스에서 그 조회를 그대로 돌릴 이유가 없어서다. 대신 문의 시점 밖의 날짜라면 못 찾는 것을 감수했고 범위를 몇 달로 넓게 잡았다.
원인 — 둘로 갈린 저장소
답을 내려다 멈춘 이유는 이 시스템의 데이터가 한 곳이 아니라는 사실이었다. 기존 스키마와는 별도로 신규 order-service 가 자기 데이터베이스를 따로 갖고 있었다.
내가 쓴 mysql 클라이언트는 기존 쪽에만 연결돼 있으므로 확인한 것은 그쪽에 없다는 것까지였다. 도구가 조용히 조사 범위를 정하고 있었고 그 사실을 모르면 0건이 없다로 읽힌다.
조치 — 어디까지 봤고 어디는 못 봤다
신규 쪽을 보려면 그쪽 관리 인터페이스를 띄우거나 ~/.my.cnf 에 조회 연결을 따로 추가해야 했다. 확인해 보니 그 서비스 컨테이너 자체가 docker ps 에 없는 상태였다.
그래서 기존 쪽에는 없고 신규 쪽은 아직 확인하지 못했으며 확인하려면 무엇이 필요한지를 함께 회신했다. 없다고 답하면 받는 쪽이 그것으로 종결하는데 실제로는 남아 있을 수 있다.
주의 — 검증 범위를 명시하기
이 요청과 함께 다른 조사 내용도 전달받았는데 그것은 이전에 누가 조사한 것이었다. 이번 조사에서 검증하지 않았으므로 그 사실을 보고에 그대로 적었다.
같이 전달받았다고 해서 그 내용까지 같이 확인한 것은 아니었다. 조회 도구가 무엇에 붙어 있는지도 INVESTIGATION.md 에 남겨서 다음 사람이 0건을 제대로 읽게 했다.
정리
- 데이터가 둘로 갈려 있으면 한쪽의 0건은 없다가 아니다
- 도구가 조용히 조사 범위를 정한다
- 도구가 무엇에 붙어 있는지를 알아야 0건을 읽을 수 있다
- 인덱스 없는 컬럼 단독 조회는 전체를 훑는다
- 예상 행 수는 추정치여도 자릿수로 판단에 쓸 수 있다
- 답은 없다가 아니라 어디까지 봤고 어디는 못 봤다로 낸다
- 없다고 답하면 받는 쪽이 그것으로 종결한다
- 같이 받은 내용이라고 같이 확인한 것이 아니다