상품에 옵션이 여럿이었다.
크기 6종
색상 4종
수량 3종
Table of contents
Open Table of contents
배경 — 조합을 미리 만들었다
처음에는 조합을 전부 미리 만들었다.
6 × 4 × 3 = 72
상품 하나에 72행이다. 이유가 있었는데 조합마다 재고가 다르기 때문이다.
크기 A · 색 B → 재고 5
크기 A · 색 C → 재고 0
행이 있어야 재고를 붙일 수 있어서 등록할 때 데카르트 곱을 전부 만들어 뒀다.
행이 곱해서 늘어났다
상품이 늘면서 이 테이블이 커졌다.
상품 1,000개 × 평균 조합 50 = 5만 행
옵션 종류가 하나 늘면 행이 그 배수로 늘어난다. 그런데 세어 보니 대부분 재고가 0이었다.
실제로 파는 조합은 일부였고 나머지는 자리만 차지하고 있었다. 안 파는 조합까지 만들어 둔 것이다.
필요할 때 만들기로 했다
방향을 바꿨다. 미리 전부 만들고 재고를 0으로 두는 대신 파는 것만 만든다.
$stock = $model->get_stock($productId, $options);
$available = $stock ? $stock->qty : 0;
조회할 때 행이 없으면 품절로 처리했다. 없음이 곧 0이다. (product_id, opt1, opt2, opt3) 에 UNIQUE KEY 를 걸어 중복도 막았다.
5만 행이 수천 행이 됐다. 대신 화면이 달라져야 했다. 전에는 행이 있으니 선택지를 목록으로 뽑았는데 이제는 행이 없는 조합이 있어 그럴 수 없다.
따로 둔 옵션 정의와 남길 것
어떤 옵션이 있는지를 따로 뒀다.
product_option
product_id
option_type 크기 / 색상
option_value A / B / C
정의와 재고를 나눈 것이다. 화면은 product_option 으로 선택지를 그리고 재고는 사용자가 고른 뒤에 조회한다.
그런데 살 수 없는 조합도 선택지에 나왔다. 크기 A 를 고르면 색상이 전부 표시되고 어떤 색을 고르면 그제야 품절이라는 것을 안다.
미리 표시하려면 조합마다 재고를 봐야 하는데 그러면 조회가 그만큼 는다.
$stocks = $model->get_all_stocks($productId);
조합마다 부르지 않고 그 상품의 재고 전부를 한 번에 가져왔는데 수천 행 전체가 아니라 그 상품 것만이라 양이 적었다.
가져온 것을 화면 쪽에서 선택지에 반영해 재고 있는 조합은 선택 가능하게 하고 없는 조합은 회색으로 뒀다. 고르기 전에 알 수 있게 된 것이다.
이 방식은 상품 하나의 조합 수가 많지 않아서 가능했다. 옵션 5종에 각 10개면 10만 조합인데 그런 상품은 없었다. 다만 언제 다시 봐야 하는지를 적어 뒀다.
한 상품의 조합이 수백을 넘으면 다시 본다
재고가 0이 된 행을 지울지도 정해야 했다. 지우면 행이 주는 대신 판 적 있는 조합인지 모르게 되고 남기면 이력이 남는다.
남기기로 했는데 팔린 적 있는 조합 자체가 정보였기 때문이다. 그리고 판 적이 있는 조합은 주문 이력이 참조하고 있어서 애초에 지울 수도 없었다. InnoDB 는 ON DELETE 를 안 적으면 NO ACTION 이 되고 그것이 RESTRICT 와 같아서 지우려 하면 ER_ROW_IS_REFERENCED_2 로 막힌다.
다만 오래 0인 것은 정리했다. NOT EXISTS 로 주문 이력이 없는 것만 골라 1년 넘게 0이면 지웠다. 조건을 붙여서 지운 것이다.
정리
- 옵션 조합을 미리 만들면 행이 곱해서 늘어난다
- 대부분이 재고 0인 안 파는 조합이었다
- 필요할 때 만들고 행이 없으면 품절로 본다
UNIQUE KEY로 조합 중복을 막는다- 화면에 선택지를 그리려면
product_option정의가 따로 필요하다 - 살 수 없는 조합을 미리 알리려면 그 상품 재고를 한 번에 가져온다
- 조합이 아주 많아지면 다시 볼 조건을 적어 둔다
- 재고가 0이 돼도 판 적 있는 조합은 남긴다
- InnoDB
FOREIGN KEY는ON DELETE생략 시RESTRICT다 NOT EXISTS로 주문 없는 것만 골라 조건을 붙여 정리한다