[최적화] 영카트 카테고리 로딩 속도 2.7배 향상 및 메모리 최적화 팁 [get_shop_category_array]
안녕하세요. 영카트 기반 쇼핑몰을 운영하면서 카테고리 호출 속도가 점차 느려지는 문제를 해결하고자 쿼리 최적화를 진행해 보았습니다. 기존 영카트 방식의 계층 구조 호출이 가진 성능 한계를 개선한 결과와 코드를 공유합니다.
제 환경은
카테고리 테이블의
row는 863개이고
depth는 4단계입니다.
1. 기존 방식의 문제점: N+1 쿼리 발생
기존 함수는 1단 카테고리를 가져온 뒤, 그 개수만큼 다시 2단 쿼리를 날리고, 또 그 개수만큼 3단 쿼리를 날리는 '재귀적 쿼리 호출(N+1 Problem)' 방식을 사용합니다.
-
카테고리 숫자가 많아질수록 DB 접속 횟수가 기하급수적으로 늘어납니다.
-
매 단계마다 별도의 쿼리를 실행하므로 실행 시간과 메모리 점유율이 동반 상승합니다.
2. 최적화 핵심: "Single Query & Reference Tree"
개선된 코드는 **단 한 번의 쿼리(Single Query)**로 모든 카테고리 데이터를 가져온 뒤, PHP의 참조(Reference, &) 연산자를 이용해 메모리 상에서 즉시 계층 구조를 조립합니다.
3. 성능 비교 결과 (Benchmark)
로컬 환경에서 카테고리 호출 시 측정한 결과입니다. (수치는 환경에 따라 다를 수 있습니다.)
| 항목 | 기존 코드 (N+1 방식) | 최적화 코드 (Single Query) | 개선 효과 |
| 실행 시간 | 0.014194... 초 | 0.005279... 초 | 약 270% 빨라짐 |
| 메모리 사용 | 12.55 MB | 7.09 MB | 약 43% 절감 |
-
시간: DB 왕복 횟수를 1회로 단축하여 응답 속도를 대폭 줄였습니다.
-
메모리: 불필요한 반복문과 임시 객체 생성을 최소화하여 메모리 효율을 극대화했습니다.
4. 최적화된 코드 (무제한 Depth 대응)
이 코드는 카테고리가 3단을 넘어 4단, 5단으로 깊어져도 별도의 코드 수정 없이 자동으로 계층을 구성합니다.
> lib > shop.data.lib.php
function get_shop_category_array($is_cache=false){
static $categories = array();
// 영카트 표준 Hook 유지
$categories = run_replace('get_shop_category_array', $categories, $is_cache);
if( $is_cache && !empty($categories) ){
return $categories;
}
// 단 한 번의 쿼리로 모든 카테고리 로드
$sql = " SELECT * FROM {$g5['yc5_category_table']}
WHERE ca_use = '1'
ORDER BY ca_id ASC ";
$result = sql_query($sql);
$refs = array();
$categories = array();
while($row = sql_fetch_array($result)) {
$row['url'] = shop_category_url($row['ca_id']);
$ca_id = $row['ca_id'];
$len = strlen($ca_id);
// 현재 노드 구조 생성
$node = array('text' => $row);
$refs[$ca_id] = $node;
if($len == 2) {
// 1단 카테고리
$categories[$ca_id] = &$refs[$ca_id];
} else {
// 부모 ID 추출 및 참조 연결 (무제한 Depth 대응)
$parent_id = substr($ca_id, 0, $len - 2);
if(isset($refs[$parent_id])) {
$refs[$parent_id][$ca_id] = &$refs[$ca_id];
}
}
}
return $categories;
}
마치며
메인 페이지나 사이드바에서 카테고리 메뉴를 호출할 때 서버 부하가 느껴진다면 이 방식을 적용해 보시길 추천드립니다. 특히 모바일 환경이나 접속자가 많은 시간대에 더 큰 효과를 볼 수 있습니다.
댓글 2개
포함 되어야 하는거 아닙니까?
고맙습니다 !!!
함수의 재귀호출이 편할 수는 있는데.. 너무 많이 돌면.. 성능에 영향을 주죠.. ^^