쿼리 캐시
쿼리 캐시(Query Cache)는 SQL 쿼리의 실행 결과(즉, 결과 집합)를 캐싱하여, 동일한 쿼리가 반복 실행될 때 DBMS가 동일 결과를 재계산하지 않고 바로 캐시된 결과를 반환해 처리 속도를 높이는 메커니즘임.
다만, 각 데이터베이스 시스템마다 구현 방식이 다르며, Plan Cache(실행 계획 캐시)와 구분되어야 함.
쿼리 캐시 동작 원리
1. SQL 텍스트 일치 확인
쿼리 캐시는 일반적으로 SQL 문장(쿼리 문자열)이 완전히 동일한 경우에만 캐시를 재사용함.
예를 들어, 공백, 대소문자, 코멘트 차이 등 미세한 텍스트 차이만 있어도 동일 쿼리로 인식되지 않을 수 있음.
2. 결과 집합 자체(로우·필드 값)를 캐시
쿼리 캐시와 실행 계획 캐시(Plan Cache)는 다름.
쿼리 캐시: “특정 쿼리 → 결과 로우 집합” 자체를 메모리에 보관
실행 계획 캐시(Plan Cache): “특정 쿼리 → 실행 계획(옵티마이저가 생성한 물리적 연산 시퀀스)”을 보관
MySQL의 전통적 ‘Query Cache’는 결과를 완전히 캐싱하기 때문에, 캐시 적중 시 DB 엔진은 추가 연산 없이 바로 결과를 돌려줌.
3. 데이터 변경에 따른 캐시 무효화
쿼리 캐시는 데이터의 무결성을 유지하기 위해, 관련 테이블의 INSERT/UPDATE/DELETE 등 DML이 일어나는 즉시(혹은 특정 조건) 해당 캐시 엔트리를 무효화(invalidation)함.
이로 인해 테이블에 변경이 잦은 환경에서는 쿼리 캐시가 자주 무효화되어, 오히려 캐시 오버헤드가 커질 수 있음.
MySQL 쿼리 캐시의 특징과 한계 : MySQL에서의 동작 (5.x~5.7)
MySQL 5.7까지는 쿼리 캐시 기능이 존재했음.
query_cache_size, query_cache_type 등의 파라미터로 캐시 크기와 동작 방식을 설정할 수 있었음.
캐시에 저장된 쿼리는 정확히 동일한 SQL 문자열일 때만 적중(match) 가능했음.
MySQL 쿼리 캐시의 특징과 한계 : 무효화와 성능 이슈
MySQL 쿼리 캐시는 테이블 단위로 무효화가 발생함.
예를 들어, 특정 테이블에 INSERT가 발생하면 해당 테이블을 참조하는 쿼리는 모두 캐시에서 제거됨.
데이터가 자주 변경되는 OLTP 환경에서는 쿼리 캐시가 오히려 병목(cache lock)을 일으키고, 캐시 히트율도 낮아 성능에 악영향을 줄 수 있었음.
MySQL 쿼리 캐시의 특징과 한계 : MySQL 8.0에서의 제거
MySQL 8.0에서는 쿼리 캐시가 완전히 제거됨.
그 주된 이유는, 동시성이 높은 환경에서 캐시 락(잠금) 충돌과 무효화 오버헤드가 심각했기 때문임.
대신, InnoDB Buffer Pool 및 실행 계획 캐시(Prepared Statement) 등을 활용하거나, 데이터 변경이 적은 특정 질의에 대해서는 애플리케이션 레벨 캐시(Redis, Memcached 등)를 사용하는 방법이 권장됨.
다른 DBMS의 쿼리 캐시 혹은 유사 기능
1. Oracle, PostgreSQL, MSSQL
일반적으로 결과 집합 자체를 DB 차원에서 전역 캐싱하는 기능은 제한적이거나 제공되지 않음.
이들 DBMS는 주로 실행 계획(Plan) 캐시나 Buffer Cache(데이터 페이지 캐싱)가 성능 개선의 핵심 역할을 함.
2. Plan Cache (실행 계획 캐시)
Oracle, SQL Server, PostgreSQL(내부적으로는 ‘플랜 캐시’ 보유), MySQL 5.7+ (Prepared Statement) 등은 “쿼리 → 최적화된 실행 계획”을 재사용함.
결과를 캐싱하는 것이 아니라 옵티마이저(Optimizer) 비용을 아껴주는 효과를 가지므로, 결과 집합이 달라져도 플랜 캐시는 재사용 가능함.
3. 애플리케이션/미들티어 캐싱
일부 DBMS에서 쿼리 결과 자체를 전역으로 캐싱하지 않는 대신, 애플리케이션 레벨 또는 미들티어(예: Redis, Memcached)에서 쿼리 결과를 캐싱하고, 데이터 변경 시 혹은 일정 TTL이 지나면 무효화하는 전략을 사용함
대규모 트래픽 환경에서 DB 부하를 줄이기에 매우 효과적임.
쿼리 캐시가 유용했던 시나리오
1. 데이터 변경이 매우 드문 환경
예를 들어, 통계 데이터, 규칙 테이블, CMS 사이트의 거의 고정된 콘텐츠 등 동일한 쿼리가 반복 실행되며, 변경이 많지 않아 무효화가 적을 경우 효과가 컸음.
2. 읽기 집약적(OLAP)에 가까운 시스템
트랜잭션보다는 조회가 주류를 이뤄, 결과 집합 캐싱이 여러 사용자에게 바로바로 재사용될 수 있는 경우.
3. 정적 보고서, 대시보드
특정 시간마다 새로 계산되는 보고서를 일시적으로 캐싱해두고, 그 사이에 동일한 요청이 들어오면 DB 부하 없이 즉시 응답.
운영 시 주의할 점
1. 캐시 적중률(Hit Ratio) 모니터링
쿼리 캐시 도입 시, 실제로 얼마나 많은 쿼리가 캐시에 적중하는지 모니터링해봐야 함.
적중률이 낮고 오히려 캐시 관리 오버헤드가 크다면 비효율적일 수 있음.
2. 무효화 정책
테이블 단위 무효화인지, 특정 파티션/트리거 기반 무효화인지 등 엔진마다 다를 수 있으며, 세분화된 무효화가 불가능하면 캐시 효율성이 떨어짐.
3. 캐시 락(Contention)
동시 쓰기가 많은 환경에서는 캐시 구조에 대한 락 경합이 발생해 오히려 성능이 저하될 가능성이 큼.
4. 대규모 결과를 캐싱하는 문제
결과 집합이 매우 클 경우, 캐시에 로딩하는 것만으로도 메모리를 많이 점유하며, 관리 비용이 커짐.
“범위 쿼리나 대용량 집합”을 무분별하게 캐싱하면 비효율적일 수 있음.
쿼리 캐시 vs 실행 계획 캐시
1. 쿼리 캐시
“쿼리 문자열과 결과 집합”이 매핑되는 저장소.
쿼리가 완벽히 동일해야 재사용.
테이블에 변경이 일어나면 관련 캐시가 무효화 → 동시성 환경에서 빈번한 무효화 가능
실제 실행(로우 검색 등) 없이 즉시 결과를 반환하므로, 낭비되는 CPU를 줄일 수 있음.
2. 실행 계획 캐시
“쿼리 파싱 및 옵티마이저 비용” 절감을 위한 캐시.
결과 집합이 아니라 물리 실행 플랜을 재사용하는 것이므로, 데이터가 변경되더라도 재사용 가능(단, 통계 변화 등으로 플랜이 바뀔 수 있음)
수행 자체는 다시 필요(각 로우 검색은 해야 함)하지만, 쿼리 최적화 과정을 생략 가능.
정리
쿼리 캐시(Query Cache)는 DBMS가 특정 SQL의 결과 집합을 메모리에 보관해, 동일 쿼리 반복 시 즉시 응답하도록 하는 기능을 말함.
MySQL이 5.7까지 제공하던 전통적 쿼리 캐시는, 데이터 변경 빈도가 낮은 환경에서는 큰 효과를 볼 수 있었지만, 실제 운영 환경(OLTP 등)에서 빈번한 무효화와 락 경합으로 인해 성능 문제가 빈번했고, 결국 MySQL 8.0에서 제거됨.
대부분의 현대 RDBMS(Oracle, PostgreSQL, SQL Server, MySQL 8.0 등)는 결과 자체를 캐싱하기보다는, 실행 계획 캐시(Plan Cache)와 버퍼 캐시를 통해 쿼리 최적화 비용과 디스크 I/O를 절감하는 방식을 주력으로 사용함.
만약 “실제로 결과 집합을 캐싱”해야 한다면, 애플리케이션 레벨에서 Redis, Memcached 같은 인메모리 DB를 이용해 데이터 변경 시점을 스스로 제어하면서 부분 무효화하는 것이 더 유연하고 효율적인 솔루션이 될 수 있음.
결국 쿼리 캐시는 읽기 전용 혹은 변경이 매우 적은 환경에서만 제한적으로 효과가 있으며, 일반적인 트랜잭션 시스템(OLTP)이나 빈번한 업데이트가 일어나는 서비스에서는 대개 이점보다 오버헤드가 더 커진다는 점이 가장 중요한 결론임.
'Database > SQL' 카테고리의 다른 글
[SQL] 데이터베이스의 커넥션 풀 (0) | 2025.01.21 |
---|---|
[SQL] 데이터베이스의 커넥션과 세션 (0) | 2025.01.20 |
[SQL] 스토리지 엔진 (0) | 2025.01.20 |
[SQL] MySQL 옵티마이저 (0) | 2025.01.20 |
[SQL] 버퍼 캐시 (0) | 2025.01.20 |