728x90
고객 검색 최적화 트러블 슈팅 경험
많은 부분이 부족할 수 있고, 제 경험을 적는 글이니 양해 부탁한다. 이번 글에서는 고객 검색 최적화 작업을 통해 경험했던 트러블 슈팅 사례를 공유하고자 한다.
배경
기존의 고객 검색은 ORM을 통해 이루어졌으며, 인덱스를 제외한 최적화가 이루어지지 않았다.(2~6초 이상)
더 세부적인 검색 요구 사항이 발생함에 따라, ORM을 쿼리문으로 변경하고 최적화에 초점을 맞추고자 했다.
전제 조건
- 고객 테이블:
- 고객 테이블의 휴대폰 번호는 하이픈이 포함된 상태로 저장됩니다.
- 고객 등록 시 하이픈 제거된 번호와 하이픈 제거된 번호가 역순으로 저장된 컬럼이 존재합니다.
- 모든 쿼리는 딕셔너리 형태로 저장됩니다.
- 하이픈 제거된 번호와 역순 번호는 STORED 가상 열로 저장됩니다.
(STORED, VIRTUAL 가상열 관련 포스트는 나중에 진행할 예정입니다.)
- 검색 가능 영역:
- 고객 번호(pk 아님), 부모 이름, 아이 이름, 부모 휴대폰 번호(뒤 8자리, 4자리 검색 가능)를 포함한 여러 세부적인 검색 요구가 있습니다. 이번 글에서는 이 중 일부만 다루겠습니다.
최적화 방법
문제점
스튜디오의 고객 테이블에는 다양한 정보가 포함되어 있다.
모든 컬럼을 검색하면 비용이 많이 발생할 수 있습니다. 따라서 필요한 컬럼만을 담는 임시 테이블을 활용하기로 결정.
해결책
- 임시 테이블 생성:
- 필요한 컬럼만 담는 임시 테이블을 생성한다. 이 테이블에는 고객 등록일, 고객 번호(pk 아님), 아기 이름, 엄마 이름, 엄마 휴대폰 번호, 아빠 이름, 아빠 휴대폰 번호, 가입 경로, 계약 건수, 촬영 건수 등이 포함된다.
- 임시 테이블은 속도를 위해 MEMORY 엔진으로 생성한다.
검색 절차:
- 임시 테이블 생성
CREATE TEMPORARY TABLE temp_erp_customer (
row_num INT UNSIGNED AUTO_INCREMENT,
customer_id_id INT NOT NULL,
customer_no VARCHAR(20),
registdate VARCHAR(20),
baby_name VARCHAR(50),
mom_name VARCHAR(50),
mom_phone VARCHAR(50),
dad_name VARCHAR(20),
dad_phone VARCHAR(20),
customer_visit1 VARCHAR(50),
customer_visit2 VARCHAR(50),
customer_visit3 VARCHAR(50),
baby_duedate VARCHAR(20),
baby_birth VARCHAR(20),
TM VARCHAR(255) NULL,
contract_count VARCHAR(20) NULL,
photo_count VARCHAR(20) NULL,
contract_totamount VARCHAR(255) NULL,
contract_payadvance VARCHAR(255) NULL,
contract_payinterim VARCHAR(255) NULL,
contract_balance VARCHAR(255) NULL,
delivery_fee VARCHAR(255) NULL,
PRIMARY KEY (row_num),
UNIQUE KEY (customer_id_id)
) ENGINE=MEMORY;
- 사용자 입력 값 준비:
- 입력 값을 두 가지 버전(정상 버전과 역순 버전)으로 만듭니다. 두 버전 모두 하이픈을 제거한다.
- 쿼리 생성:
- 검색 가능한 필드들에 대해 딕셔너리 형태로 쿼리를 저장합니다.
_dict["WHERE"] += f"""
AND (
customer.customer_no = '{_str}'
OR customer.mom_name LIKE '%{_str}%'
OR customer.dad_name LIKE '%{_str}%'
OR customer.baby_name = '%{_str}%'
OR customer.mom_phone_without_hyphen LIKE '%{_str}'
OR customer.dad_phone_without_hyphen LIKE '%{_str}'
OR customer.mom_phone_without_hyphen_reverse LIKE '{_str2}%'
OR customer.dad_phone_without_hyphen_reverse LIKE '{_str2}%'
)
"""
_dict['LIMIT'] += f"""
LIMIT {DATA.get('limit_start')}, {DATA.get('limit_end')}
"""
LIMIT를 활용하여 최대한 적은 데이터를 삽입하도록 한다.
3.인덱스:
- 엄마와 아빠 이름에는 LIKE를 사용했습니다. 인덱스를 타지 않아도 된다는 판단하에 데이터 정확성을 위해 선택했습니다. 성능에 큰 영향을 미치지 않을 것이라고 판단했습니다.
4.휴대폰 번호 최적화:
- 하이픈이 제거된 컬럼을 조회하여 성능을 최적화했습니다.
5. 검색 결과 임시 테이블에 삽입:
_dict['INSERT'] = """
INSERT INTO temp_erp_customer (
customer_id_id, customer_no, registdate, baby_name, mom_name, mom_phone, dad_name, dad_phone, customer_visit1,
customer_visit2, customer_visit3, baby_duedate, baby_birth
)
"""
6. 결과 조회 및 리턴:
- 임시 테이블에서 데이터를 조회하고 리턴합니다.
SELECT *
FROM temp_erp_customer
7. 임시 테이블 정리:
- 세션 종료 시 임시 테이블은 자동으로 사라집니다.
하지만 오류를 대비하여 검색할 때마다 임시 테이블 데이터를 제거하고, 위의 과정을 재 진행 합니다.
if table_exists("temp_erp_customer"):
# 테이블이 존재하면 데이터를 삭제합니다.
execute_query("DELETE FROM temp_erp_customer;", "delete_temp_table")
결론
이번 최적화 작업을 통해 고객 데이터(150만개 이상) 검색 속도 (0초대를 유지) 를 크게 향상시킬 수 있었다.
임시 테이블을 활용하여 필요한 데이터만 처리함으로써 비용을 절감하고, 사용자 경험을 개선할 수 있엇다.
이 경험을 바탕으로 다양한 최적화 기법을 지속적으로 탐구하고 적용해 나갈 예정이며.
후에는 STORED, VIRTUAL (가상열)과 InnoDB, MEMORY 엔진 관련 포스트도 진행할 예정이며.
MYSQL 관련 기능 및 공부하였던 내역을 공유 하고자 한다.
더 깊이 있는 DB 지식을 공유할 수 있도록 하겠습니다.
감사합니다.
728x90
'트러블 슈팅' 카테고리의 다른 글
MYSQL 엔진 성능 최적화 (0) | 2024.07.28 |
---|---|
STORED 컬럼을 이용한 쿼리 최적화 (0) | 2024.03.09 |
[MySQL] Pagination 방법론 (0) | 2024.03.03 |
RDBMS Index (1) | 2024.02.18 |
인증 토큰: 관리자와 사용자 간의 인증 비교 (1) | 2023.12.30 |