DB

[MySQL] (JSON5️⃣) JSON 쿼리 성능 튜닝 전략: 인덱싱과 최적화 팁

인생아 2025. 7. 17. 20:33
반응형

MySQL에서 JSON은 유연한 대신 성능 이슈를 동반한다.
특히 WHERE 절에서 자주 조회하거나 JOIN에 얽히면 쿼리 속도가 급격히 느려질 수 있다.

⚠️ JSON 쿼리가 느려지는 이유

  • JSON 컬럼은 일반적인 인덱스를 직접 생성할 수 없음
  • profile->'$.name' 같은 경로 탐색은 모든 행을 검사해야 함
  • JSON_EXTRACT, JSON_CONTAINS는 함수 호출 비용이 크다

즉, JSON 컬럼에 조건이 붙으면 인덱스가 무시되는 경우가 많다

반응형

✅ 해결 전략 1: 생성 컬럼(Generated Column) 활용

생성 컬럼은 JSON 내부 값을 꺼내 일반 컬럼처럼 쓰게 해준다.
그리고 여기에 인덱스를 걸 수 있다.

ALTER TABLE users
ADD COLUMN nickname VARCHAR(100)
       GENERATED ALWAYS AS (JSON_UNQUOTE(profile->'$.nickname')) STORED,
ADD INDEX idx_nickname (nickname);

이제 아래 쿼리는 인덱스를 탄다.

SELECT * FROM users WHERE nickname = 'cooluser';

STORED 옵션은 물리적으로 저장되어 성능이 더 좋음
✅ 자주 조회하는 JSON 필드는 이렇게 분리해두는 게 베스트

✅ 해결 전략 2: JSON 컬럼 자체를 조건에서 제외

  • JSON은 저장용으로만 쓰고
  • 실제 쿼리는 정규 컬럼에 저장된 값만 사용하는 구조로 변경
-- 잘못된 구조
SELECT * FROM orders
WHERE JSON_EXTRACT(order_meta, '$.status') = 'shipped';

-- 추천 구조
-- status 값을 별도 컬럼으로 분리
SELECT * FROM orders
WHERE status = 'shipped';

✅ 쿼리는 심플하고 빠르게 유지, JSON은 옵션/부가 정보 저장용으로 활용

✅ 해결 전략 3: WHERE 조건 최소화 + LIMIT 적극 활용

JSON을 조건에 쓰더라도 불가피하다면
결과 범위를 최소화하거나 LIMIT을 활용해 부하를 줄여야 한다.

SELECT * FROM users
WHERE JSON_UNQUOTE(profile->'$.job') = 'developer'
LIMIT 100;

✅ 데이터 양이 많을수록 LIMIT이 체감 속도에 큰 영향을 줌

✅ 해결 전략 4: 복합 조건으로 인덱스 유도

JSON 조건 단독으론 느리지만
다른 일반 컬럼과 함께 쓸 경우 인덱스를 활용할 수도 있다.

SELECT * FROM users
WHERE user_type = 'premium'
AND JSON_EXTRACT(profile, '$.marketing_optin') = 'true';

✅ user_type이 먼저 필터링되면서 스캔 범위를 줄여준다

반응형

🧠 실무 적용 예시

-- 자주 쓰는 검색 조건은 생성 컬럼으로 분리
ALTER TABLE products
ADD COLUMN brand VARCHAR(100)
       GENERATED ALWAYS AS (JSON_UNQUOTE(details->'$.brand')) STORED,
ADD INDEX idx_brand (brand);
-- JSON 조건을 쿼리에서 완전히 제거하고 정규화
ALTER TABLE settings ADD COLUMN dark_mode BOOLEAN;
-- 배치 작업으로 dark_mode 값 추출 후 채우기

📌 정리

전략 설명
생성 컬럼 JSON 내부 값을 일반 컬럼으로 꺼내 인덱스 적용 가능
조건 최소화 WHERE에 JSON을 쓰는 범위를 줄이기
JSON 필드 분리 자주 쓰는 값은 별도 컬럼으로 분리 (정규화)
복합 조건 활용 일반 컬럼과 함께 쓰면 범위 필터링 가능

MySQL은 JSON 성능을 계속 개선 중이지만,
지금으로선 쿼리 최적화를 위한 구조적 설계가 가장 중요하다.

📘 공식 문서 참고

https://dev.mysql.com/doc/refman/8.0/en/generated-columns.html

 

반응형