이전에 제가 소개드린 **스냅샷 구조 (링크)** 를 따르든 또는 그렇지 않든, 결국 데이터는 시간 값이 굉장히 중요해집니다. 어떤 물건을 샀다면, 구매한 시간이 언제인지를 볼 것이고, 장바구니에 담고 결제가 이루어지기까지 걸린 시간을 볼 겁니다. 그 외에도 물건을 보고 장바구니에 담은 시간은 얼마나 걸렸는지, 각 과정 사이 사이에 걸린 시간을 보겠죠. 마지막으로 특정 시간 대에 일어난 액션들을 봅니다. 결과적으로 우리는,
시간 값을 가지고 이렇게 세 가지의 인사이트를 파악할 수 있습니다. 다만, 이번에 제가 설명드리고 싶은 것은 그로스 해킹적인 이야기가 아닙니다. 이번에 제가 알려드리고 싶은 것은, 백엔드 개발자로서 시간 값을 올바르게 저장하는 방법에 관하여 입니다. 정말 사소하지만, 알아두면 정말 많은 게 달라집니다. 아래 예시를 봅시다.
우리는 물건을 구매한 시간을 order 같은 테이블을 보고 알 수 있을 겁니다. 테이블 이름은 정의한 사람마다 다르겠지만, 이런 종류의 테이블에서는 주문이 발생한 시간마다 생성되는 Record가 생길 겁니다. 그리고 그 Record들을 통해서 어떤 시간 대에 생성되었는지를 볼 수 있을 겁니다. 대부분의 경우 이런 칼럼은 이름을 createdAt으로 해둡니다. 하지만 이 때, 유저가 여러 개의 물건을 장바구니에 넣고 한꺼번에 결제했다고 해봅시다. 동시간 대에 주문, 결제를 의미하는 Record가 생성이 되었을까요? 안타깝게도 대부분의 경우 그렇지 않을 겁니다. 코드가 아래와 같다고 해봅시다. 아래 코드는 자바스크립트지만 맥락은 이해할 수 있으실 겁니다.
for (let i = 0; i < carts.length; i++) {
var cart = carts[i];
await createOrder(cart); // 장바구니 1개씩을 돌면서 생성
}
대부분의 경우, MYSQL은 CURRENT_TIMESTAMP와 같이, 현재 시간이 들어가게 설정됩니다. 따라서 매우 미세한 밀리 초 단위로 주문의 시간이 다르게 들어갈 수 밖에 없습니다. 어쩌면 백엔드 개발자들에겐 이게 그다지 이상한 일이 아닐지 모르고, 생성된 시간을 의미하는 칼럼에 정확한 생성 시간을 넣었다고 여겨질지 모릅니다. 하지만 이렇게 생성된 order 레코드들은 각기 다른 시간이 들어가기 때문에 추후 데이터 분석을 망칩니다. 예를 들어 데이터 분석가의 입장에서 이렇게 생각해봅시다.
“동시에 구매가 일어난 상품들을 보면 MD에게 추천 상품 데이터로 제공해줄 수 있을 거야. 예를 들어, 빵을 샀을 때 우유가 같이 팔릴 확률이 높다면 빵을 장바구니에 담은 고객에겐 장바구니 페이지에 띄워서 우유도 사라고 안내해줄 수 있겠지?”
그리고 데이터 분석가는 쿼리를 날려 자신의 생각이 맞는지 봅니다. 하지만 동시에 구매한 상품들은 없었습니다. 데이터 분석가는 이내 자신의 생각이 틀렸다고 생각하고, ‘고객들은 물건을 1개씩 개별적으로 사는 경향이 크군.’ 잘못된 판단을 내릴 수도 있습니다. 실제로는 아주 작은 밀리 초 단위로 다를 뿐인데도요. 뒤늦게 이러한 사실을 깨달은 데이터 분석가는 더욱 복잡한 쿼리를 날릴 수 밖에 없습니다.
“동시에 물건을 샀다는 정의를, 어떠한 물건을 기준으로 interval하게 1초 이내로 일어난 행위에 대해서로 잡는다. 예를 들어, 빵을 구매하기 전 1초 전에 우유를 샀다면 동시에 구매한 것이고, 마찬가지로 우유를 구매하기 1초 전에 잼을 샀다면 그 또한 동시에 산 것이다. 이 정도면 됐겠지?“