Statement Memory란 무엇인가
SAP HANA의 Statement Memory는 단일 SQL 문(statement)이 실행되는 동안 소비할 수 있는 최대 메모리 양을 제어하는 메모리 관리 체계다. 컬럼스토어 기반의 HANA는 복잡한 집계, 조인, 분석 쿼리를 인메모리로 처리하기 때문에, 잘못 작성된 쿼리 하나가 수십 GB의 메모리를 순식간에 점유할 수 있다. Statement Memory 제한이 없다면 단일 쿼리가 전체 시스템 메모리를 고갈시키고 다른 모든 세션과 서비스를 다운시킨다.
HANA는 Statement Memory를 세 계층으로 나누어 관리한다. 첫째, 시스템 전역(Global) 수준에서 모든 SQL 문이 공유하는 풀 크기를 설정한다. 둘째, 사용자(User) 수준에서 특정 사용자가 실행하는 쿼리별 한도를 지정한다. 셋째, 세션(Session) 수준에서 현재 연결에만 임시로 적용되는 제한을 설정한다. 이 세 계층이 겹칠 때는 가장 낮은(tight) 값이 실제 제한으로 작동한다.
한도 초과 시 발생하는 현상
Statement Memory 한도를 초과하면 HANA는 즉시 해당 쿼리를 강제 종료하고 오류를 반환한다. 클라이언트 측에서는 아래와 유사한 에러 메시지를 받게 된다.
SAP DBTech JDBC: [2048]: column store error:
search table error: [6944] Out of memory: statement memory limit exceeded
(statement memory limit: 5368709120 bytes, peak statement memory: 5621145600 bytes)
오류 코드 6944는 Statement Memory 한도 초과를 의미한다. 메시지에는 현재 설정된 한도(bytes)와 쿼리가 실제로 사용하려 했던 피크 메모리 크기가 함께 출력된다. 이 두 숫자를 비교하면 얼마나 한도를 초과했는지 즉시 파악할 수 있다.
한도 초과 외에도 시스템이 메모리 압박 상태에 빠지면 HANA의 Out-of-Memory Manager가 개입하여 자동으로 Statement Memory를 줄이거나 특정 쿼리를 킬한다. 이 경우는 오류 코드 4(general out-of-memory)가 반환되며, 원인 추적이 Statement Memory 한도 초과보다 더 복잡해진다.
현재 Statement Memory 설정 확인
먼저 현재 시스템에 적용된 Statement Memory 설정을 조회해야 한다. HANA Studio, DBACOCKPIT, 또는 직접 SQL로 확인할 수 있다.
-- 전역 Statement Memory 한도 (bytes 단위)
SELECT KEY, VALUE
FROM M_CONFIGURATION_PARAMETER_VALUES
WHERE SECTION = 'memorymanager'
AND KEY IN ('statement_memory_limit', 'enable_statement_memory_tracking');
-- GB 단위로 변환해서 보기
SELECT
KEY,
CAST(VALUE AS BIGINT) / 1073741824 AS LIMIT_GB
FROM M_CONFIGURATION_PARAMETER_VALUES
WHERE SECTION = 'memorymanager'
AND KEY = 'statement_memory_limit'
AND LAYER_NAME = 'SYSTEM';
statement_memory_limit 값이 0이면 시스템 전역 제한이 없는 상태다. 하지만 이 상태를 운영 환경에서 사용하는 것은 위험하다. 반드시 적절한 한도를 설정해야 한다.
사용자별 Statement Memory 한도는 별도로 조회한다.
-- 특정 사용자의 Statement Memory 한도 확인
SELECT
USER_NAME,
STATEMENT_MEMORY_LIMIT
FROM SYS.USERS
WHERE USER_NAME = 'MYAPP_USER';
-- 전체 사용자의 Statement Memory 설정 한번에 보기
SELECT
USER_NAME,
STATEMENT_MEMORY_LIMIT,
STATEMENT_THREAD_LIMIT
FROM SYS.USERS
WHERE STATEMENT_MEMORY_LIMIT IS NOT NULL
ORDER BY STATEMENT_MEMORY_LIMIT DESC;
Statement Memory 한도 설정 방법
시스템 전역 한도는 ALTER SYSTEM ALTER CONFIGURATION으로 설정한다. 값은 바이트 단위이며 정수로 입력한다.
-- 전역 Statement Memory 한도를 20GB로 설정 (시스템 레이어)
ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'SYSTEM')
SET ('memorymanager', 'statement_memory_limit') = '21474836480'
WITH RECONFIGURE;
-- 설정 즉시 적용 여부 확인
SELECT KEY, VALUE
FROM M_CONFIGURATION_PARAMETER_VALUES
WHERE SECTION = 'memorymanager'
AND KEY = 'statement_memory_limit'
AND LAYER_NAME = 'SYSTEM';
특정 사용자에게 Statement Memory 한도를 적용할 때는 ALTER USER를 사용한다.
-- REPORT_USER에게 8GB Statement Memory 한도 적용 (단위: MB)
ALTER USER REPORT_USER STATEMENT MEMORY LIMIT 8192;
-- 확인
SELECT USER_NAME, STATEMENT_MEMORY_LIMIT
FROM SYS.USERS
WHERE USER_NAME = 'REPORT_USER';
세션 레벨 임시 설정은 현재 커넥션에만 적용되며 세션 종료 시 사라진다.
-- 현재 세션에만 Statement Memory 4GB로 임시 제한
SET 'statement_memory_limit' = '4294967296';
Statement Memory Tracking으로 과다 소비 쿼리 찾기
Statement Memory 한도 초과가 자주 발생한다면 어떤 쿼리가 메모리를 많이 쓰는지 추적해야 한다. HANA는 Statement Memory Tracking 기능을 통해 각 쿼리의 메모리 소비를 기록한다.
-- Statement Memory Tracking 활성화
ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'SYSTEM')
SET ('memorymanager', 'enable_statement_memory_tracking') = 'true'
WITH RECONFIGURE;
활성화 후에는 M_SQL_PLAN_CACHE와 M_EXPENSIVE_STATEMENTS에서 메모리 소비량을 조회할 수 있다.
-- 메모리 소비 상위 10개 쿼리 (플랜 캐시 기준)
SELECT TOP 10
STATEMENT_HASH,
EXECUTION_COUNT,
ROUND(MAX_PEAK_MEMORY_SIZE / 1073741824.0, 2) AS MAX_PEAK_GB,
ROUND(AVG_PEAK_MEMORY_SIZE / 1073741824.0, 2) AS AVG_PEAK_GB,
SUBSTRING(STATEMENT_STRING, 1, 120) AS STMT_PREVIEW
FROM M_SQL_PLAN_CACHE
WHERE MAX_PEAK_MEMORY_SIZE > 0
ORDER BY MAX_PEAK_MEMORY_SIZE DESC;
-- 한도 초과로 종료된 쿼리 이력 (Expensive Statements)
SELECT
START_TIME,
DURATION_MICROSEC,
ROUND(MEMORY_SIZE / 1073741824.0, 2) AS MEMORY_GB,
ERROR_CODE,
SUBSTRING(STATEMENT_STRING, 1, 200) AS STMT
FROM M_EXPENSIVE_STATEMENTS
WHERE ERROR_CODE = 6944
ORDER BY START_TIME DESC
LIMIT 20;
M_EXPENSIVE_STATEMENTS는 기본적으로 실행 시간이 길거나 오류가 발생한 쿼리를 기록한다. 에러 코드 6944(Statement Memory 초과)를 필터링하면 문제 쿼리 목록을 빠르게 얻을 수 있다.
한도 초과의 근본 원인 분석과 쿼리 최적화
단순히 한도를 올리는 것은 임시 해결책이다. 근본 원인을 찾아 쿼리를 최적화해야 한다. Statement Memory 과다 소비의 주요 원인은 다음과 같다.
1. 조인 순서 및 방식 문제
HANA 옵티마이저가 잘못된 조인 순서를 선택하면 중간 결과셋이 기하급수적으로 커진다. EXPLAIN PLAN으로 실행 계획을 확인하고 조인 카디널리티를 검토해야 한다.
-- 실행 계획 확인
EXPLAIN PLAN FOR
SELECT
o.ORDER_ID,
c.CUSTOMER_NAME,
SUM(oi.QUANTITY * oi.UNIT_PRICE) AS TOTAL_AMOUNT
FROM ORDERS o
JOIN CUSTOMERS c ON o.CUSTOMER_ID = c.CUSTOMER_ID
JOIN ORDER_ITEMS oi ON o.ORDER_ID = oi.ORDER_ID
WHERE o.ORDER_DATE >= ADD_MONTHS(CURRENT_DATE, -3)
GROUP BY o.ORDER_ID, c.CUSTOMER_NAME;
SELECT * FROM EXPLAIN_PLAN_TABLE ORDER BY OPERATOR_ID;
2. 파티셔닝 프루닝 실패
파티션 테이블에서 파티션 키를 조건에 사용하지 않으면 전체 파티션을 스캔한다. 이 경우 메모리 소비가 급격히 증가한다.
-- BAD: 파티션 컬럼에 함수 적용 → 파티션 프루닝 실패
SELECT * FROM SALES_FACT
WHERE YEAR(SALE_DATE) = 2025;
-- GOOD: 범위 조건으로 변환 → 파티션 프루닝 작동
SELECT * FROM SALES_FACT
WHERE SALE_DATE >= '2025-01-01'
AND SALE_DATE < '2026-01-01';
3. 중간 결과셋 비대화
DISTINCT, GROUP BY, ORDER BY 없이 대용량 테이블을 조인하면 중간 결과셋이 디스크보다 메모리에 먼저 올라와 Statement Memory를 소진한다. WHERE 조건을 조인 전에 필터링되도록 쿼리를 재작성해야 한다.
-- BAD: 대용량 테이블 풀스캔 후 조인
SELECT t.TRANSACTION_ID, a.ACCOUNT_NAME
FROM TRANSACTIONS t
JOIN ACCOUNTS a ON t.ACCOUNT_ID = a.ACCOUNT_ID;
-- GOOD: 서브쿼리로 먼저 범위 축소
SELECT t.TRANSACTION_ID, a.ACCOUNT_NAME
FROM (
SELECT TRANSACTION_ID, ACCOUNT_ID
FROM TRANSACTIONS
WHERE TRANSACTION_DATE >= '2025-01-01'
AND TRANSACTION_STATUS = 'PENDING'
) t
JOIN ACCOUNTS a ON t.ACCOUNT_ID = a.ACCOUNT_ID;
운영 환경에서의 Statement Memory 모니터링 구성
Statement Memory 문제를 사전에 감지하려면 지속적인 모니터링이 필요하다. HANA Alert을 설정하거나 주기적인 통계 수집 쿼리를 스케줄링한다.
-- 현재 실행 중인 Statement의 메모리 사용 현황
SELECT
SESSION_ID,
USER_NAME,
STATEMENT_ID,
ROUND(MEMORY_SIZE / 1073741824.0, 2) AS CURRENT_MEMORY_GB,
START_TIME,
DURATION / 1000000 AS DURATION_SEC,
SUBSTRING(STATEMENT_STRING, 1, 100) AS STMT_PREVIEW
FROM M_ACTIVE_STATEMENTS
WHERE MEMORY_SIZE > 1073741824
ORDER BY MEMORY_SIZE DESC;
이 쿼리를 모니터링 도구에 연결하거나 SAP HANA Cockpit의 SQL Statement Analysis 화면에서 실시간으로 확인할 수 있다. 한도의 80% 이상을 사용하는 쿼리가 감지되면 즉시 알림을 받도록 임계값을 설정한다.
-- 전체 메모리 대비 Statement Memory 비율 확인
SELECT
FREE_PHYSICAL_MEMORY / 1073741824.0 AS FREE_PHYSICAL_GB,
TOTAL_MEMORY_USED_SIZE / 1073741824.0 AS TOTAL_USED_GB,
STATEMENT_MEMORY_LIMIT / 1073741824.0 AS STMT_LIMIT_GB
FROM M_HOST_RESOURCE_UTILIZATION
CROSS JOIN (
SELECT CAST(VALUE AS BIGINT) AS STATEMENT_MEMORY_LIMIT
FROM M_CONFIGURATION_PARAMETER_VALUES
WHERE SECTION = 'memorymanager'
AND KEY = 'statement_memory_limit'
AND LAYER_NAME = 'SYSTEM'
) cfg;
HANA 2.0 SPS07 이후 변경 사항과 주의점
HANA 2.0 SPS07부터 Statement Memory 관련 파라미터 이름과 단위가 일부 변경되었다. 기존에는 statement_memory_limit가 바이트 단위였으나, 특정 패치 레벨부터 GB 단위를 직접 지원하는 파라미터가 추가되었다. SAP Note 2154870(HANA Memory Overview)와 SAP Note 1999997(FAQ: SAP HANA Memory)을 릴리즈 버전에 맞게 확인해야 한다.
멀티테넌트(MDC) 환경에서는 각 테넌트 데이터베이스마다 Statement Memory 한도를 독립적으로 설정할 수 있다. 시스템 DB와 테넌트 DB의 설정이 중첩될 때는 낮은 값이 우선하므로, 테넌트별 리소스 관리 계획에 맞게 설정해야 한다.
-- 멀티테넌트 환경: 특정 테넌트의 Statement Memory 한도 설정
ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'DATABASE', 'TENANT_PRD')
SET ('memorymanager', 'statement_memory_limit') = '10737418240'
WITH RECONFIGURE;
Statement Memory 문제 해결 체크리스트
Statement Memory 한도 초과 오류가 발생했을 때 순서대로 점검할 항목을 정리한다.
첫째, M_EXPENSIVE_STATEMENTS에서 오류 코드 6944로 필터링해 문제 쿼리를 특정한다.
둘째, EXPLAIN PLAN으로 해당 쿼리의 실행 계획을 확인하고 풀스캔·조인 순서 문제를 파악한다.
셋째, 파티션 프루닝이 작동하는지 확인한다. 파티션 컬럼에 함수 적용이 없는지 검토한다.
넷째, WHERE 조건을 최대한 앞으로 당겨 중간 결과셋 크기를 줄인다.
다섯째, 최적화 후에도 한도가 빡빡하다면 해당 사용자에 대해서만 한도를 조정하되, 시스템 전역 한도는 건드리지 않는다.
여섯째, M_SQL_PLAN_CACHE에서 동일 쿼리의 평균·최대 피크 메모리를 수집해 변화를 트래킹한다.
-- 문제 쿼리 최종 확인: 최근 1시간 내 Statement Memory 초과 빈도
SELECT
STATEMENT_HASH,
COUNT(*) AS ERROR_COUNT,
MAX(MEMORY_SIZE) / 1073741824.0 AS MAX_MEM_GB,
MIN(START_TIME) AS FIRST_SEEN,
MAX(START_TIME) AS LAST_SEEN,
SUBSTRING(STATEMENT_STRING, 1, 150) AS STMT_PREVIEW
FROM M_EXPENSIVE_STATEMENTS
WHERE ERROR_CODE = 6944
AND START_TIME >= ADD_SECONDS(CURRENT_TIMESTAMP, -3600)
GROUP BY STATEMENT_HASH, STATEMENT_STRING
ORDER BY ERROR_COUNT DESC;
댓글 0
아직 댓글이 없습니다.