창고 피킹·패킹 최적화: 처리 속도를 2배로 높이는 운영 설계

이커머스

창고 운영피킹 최적화WMS물류 자동화풀필먼트

이 글은 누구를 위한 것인가

  • 주문 처리 속도가 느려 당일 출고 마감에 자주 실패하는 팀
  • 오피킹(잘못된 상품 집기) 비율이 높아 CS가 늘어나는 팀
  • 창고 WMS를 도입하거나 개선하려는 운영/개발 담당자

들어가며

창고에서 작업자가 주문 1개당 창고를 걸어다니는 거리가 줄수록 처리 속도는 올라간다. 피킹 경로 최적화만으로도 처리 속도를 30-50% 개선할 수 있다.

이 글은 bluefoxdev.kr의 이커머스 물류 운영 가이드 를 참고하여 작성했습니다.


1. 피킹 방식 비교

[피킹 방식 선택 가이드]

1. 싱글 오더 피킹 (Single Order):
   방식: 주문 1개씩 처리
   적합: 소량 고품질 상품, 맞춤 패키징
   단점: 이동 거리 최대

2. 배치 피킹 (Batch Picking):
   방식: 여러 주문을 묶어서 한 번에 피킹
   적합: 주문량 많고 SKU 수 제한적
   장점: 이동 거리 50-70% 감소
   단점: 분류 작업 추가

3. 존 피킹 (Zone Picking):
   방식: 창고를 구역 분할, 구역별 담당자
   적합: 대형 창고, 많은 SKU
   장점: 전문화, 빠름
   단점: 구역 간 합산 작업

4. 웨이브 피킹 (Wave Picking):
   방식: 시간대별 주문을 묶어 일괄 처리
   적합: 마감 시간이 있는 운영
   장점: 출고 마감 시간 준수

[권장]
  일 1000건 미만: 배치 피킹
  일 1000건 이상: 존 + 웨이브 조합

2. 피킹 경로 최적화

from typing import NamedTuple

class Location(NamedTuple):
    aisle: str   # 통로 (A, B, C...)
    row: int     # 행 번호
    shelf: int   # 선반 번호

def optimize_picking_route(pick_list: list[dict]) -> list[dict]:
    """
    S자형 경로로 피킹 순서 최적화
    통로를 순서대로, 짝수 통로는 역방향으로
    """
    # 위치 파싱
    items_with_location = []
    for item in pick_list:
        loc = parse_location(item["location"])  # "A-03-2" → Location("A", 3, 2)
        items_with_location.append({"item": item, "location": loc})
    
    # 통로 그룹화
    aisles = {}
    for entry in items_with_location:
        aisle = entry["location"].aisle
        if aisle not in aisles:
            aisles[aisle] = []
        aisles[aisle].append(entry)
    
    # S자 경로: 통로 순서대로, 짝/홀에 따라 방향 다름
    optimized = []
    for i, aisle in enumerate(sorted(aisles.keys())):
        items_in_aisle = aisles[aisle]
        # 짝수 통로: 낮은 행 → 높은 행
        # 홀수 통로: 높은 행 → 낮은 행 (S자)
        reverse = (i % 2 == 1)
        sorted_items = sorted(
            items_in_aisle,
            key=lambda x: x["location"].row,
            reverse=reverse
        )
        optimized.extend([entry["item"] for entry in sorted_items])
    
    return optimized

def create_batch_pick_list(orders: list[dict], batch_size: int = 20) -> list[list[dict]]:
    """주문을 배치로 묶어 pick list 생성"""
    # 공통 SKU를 가진 주문끼리 묶기
    batches = []
    current_batch = []
    
    for order in orders:
        if len(current_batch) >= batch_size:
            batches.append(create_consolidated_pick_list(current_batch))
            current_batch = []
        current_batch.append(order)
    
    if current_batch:
        batches.append(create_consolidated_pick_list(current_batch))
    
    return batches

def create_consolidated_pick_list(orders: list[dict]) -> dict:
    """여러 주문의 아이템을 SKU별로 합산"""
    consolidated = {}
    
    for order in orders:
        for item in order["items"]:
            sku = item["sku"]
            if sku not in consolidated:
                consolidated[sku] = {
                    "sku": sku,
                    "location": item["location"],
                    "total_qty": 0,
                    "order_ids": [],
                }
            consolidated[sku]["total_qty"] += item["quantity"]
            consolidated[sku]["order_ids"].append(order["id"])
    
    pick_list = list(consolidated.values())
    return {
        "orders": [o["id"] for o in orders],
        "pick_list": optimize_picking_route(pick_list),
    }

3. 오피킹 방지 (바코드 검증)

async def verify_pick(pick_id: str, scanned_barcode: str, picker_id: str) -> dict:
    """피킹 시 바코드 스캔 검증"""
    
    pick_item = await get_pick_item(pick_id)
    expected_barcode = pick_item["product_barcode"]
    
    if scanned_barcode == expected_barcode:
        # 정상 피킹
        await update_pick_status(pick_id, "picked", picker_id)
        return {"success": True, "next_location": get_next_pick_location(pick_id)}
    else:
        # 오피킹 경고
        await log_pick_error(pick_id, scanned_barcode, picker_id)
        return {
            "success": False,
            "error": "잘못된 상품입니다",
            "expected_sku": pick_item["sku"],
            "expected_location": pick_item["location"],
        }

마무리

피킹 최적화는 기술보다 프로세스가 먼저다. 배치 피킹과 S자 경로 최적화만으로도 작업 효율이 크게 오른다. 오피킹은 바코드 스캔 검증으로 거의 제거할 수 있다. WMS 도입 전에도 엑셀로 배치 피킹 리스트를 만드는 것부터 시작해볼 수 있다.