전체 글
[MSSQL] DISTINCT가 감추는 Sort 비용과 근본 원인 제거 절차
DISTINCT: 실무적 정의와 운영상 중요성MSSQL에서 DISTINCT는 SELECT 결과 집합에서 중복된 행을 제거하는 키워드이다. 옵티마이저는 DISTINCT를 처리할 때 결과 행 전체를 정렬해 인접한 중복 행을 비교하는 Sort 연산자를 사용하거나, 행을 해시 테이블에 적재해 중복 여부를 판단하는 Hash Match (Aggregate) 연산자를 사용한다. 두 방식 모두 결과 집합 전체를 메모리 또는 TempDB에 올려야 하므로 원본 쿼리에는 없던 연산 비용이 추가로 발생한다.실무에서는 DISTINCT가 정당한 비즈니스 요구가 아니라 JOIN 조건 오류나 데이터 모델의 정합성 결함을 감추는 용도로 남용되는 경우가 많다. 원인을 찾지 않고 DISTINCT로 증상만 없애면 쿼리는 정상 동작하는 것처..
[MySQL] COUNT(DISTINCT) 임시 테이블 비용과 사전 집계 최적화 기준
COUNT(DISTINCT): 실무적 정의와 운영상 중요성MySQL에서 COUNT(DISTINCT expression)은 조건을 만족하는 행에서 중복되지 않은 값의 개수를 반환하는 집계 함수이다. 일반 COUNT(*)와 달리 입력값의 중복 여부를 판별해야 하므로 정렬, 임시 자료구조 또는 인덱스 기반 접근이 추가될 수 있다.고유값의 수와 집계 대상 행이 증가하면 중복 제거 상태도 커진다. 이 상태가 메모리 안에서 처리되지 못하면 내부 임시 테이블의 디스크 전환과 추가 I/O가 발생할 수 있다. 운영 환경에서는 긴 응답 시간에 그치지 않고 동시 쿼리의 버퍼 풀 경쟁과 디스크 I/O 병목으로 이어진다.고유값 집계에서 임시 테이블 사용을 줄이는 순서는 명확하다. 먼저 WHERE 절로 읽는 행을 줄이고, 필터와..
[MSSQL] Hash Aggregate와 Stream Aggregate 선택 조건: 정렬 입력·그룹 수 기준
Hash Aggregate와 Stream Aggregate: 실무적 정의와 운영상 중요성MSSQL에서 집계 연산자는 GROUP BY, DISTINCT, COUNT, SUM 같은 연산을 실제로 수행한다. 실행 계획에서는 주로 Hash Match (Aggregate) 또는 Stream Aggregate로 나타난다. 두 연산자는 같은 결과를 반환하지만 입력 순서, 그룹 수, 메모리 사용 방식이 다르다.Stream Aggregate는 그룹 키 순서로 정렬된 입력을 순차적으로 읽으며 집계한다. Hash Aggregate는 입력 행의 그룹 키로 해시 테이블을 만들고 같은 키를 하나의 버킷에 모아 집계한다. 따라서 정렬된 입력이 이미 존재하면 Stream Aggregate가 유리하고, 정렬되지 않은 대량 입력에서는 ..
[MySQL] GROUP BY Using temporary와 Using filesort를 줄이는 인덱스 설계 조건
GROUP BY: 실무적 정의와 운영상 중요성MySQL에서 GROUP BY는 동일한 그룹 키를 가진 행을 묶고 COUNT, SUM, MIN, MAX 같은 집계 함수를 계산하는 구문이다. 입력 행이 그룹 키 순서로 공급되지 않으면 MySQL은 그룹을 구성하기 위한 중간 작업을 수행해야 한다. 이때 실행 계획의 Extra에 Using temporary 또는 Using filesort가 표시될 수 있다.Using temporary는 중간 결과를 임시 테이블에 기록한다는 의미이다. Using filesort는 인덱스 순서만으로 요구된 순서를 만들지 못해 별도의 정렬 단계가 필요하다는 의미이다. filesort라는 이름이 항상 디스크 정렬을 뜻하지는 않지만, 대상 행이 증가하면 정렬 버퍼 사용과 디스크 I/O 병..
[MSSQL] OFFSET FETCH를 키셋 페이징으로 대체하는 정렬 키와 인덱스 설계
OFFSET FETCH와 키셋 페이징: 실무적 정의와 운영상 중요성SQL Server에서 OFFSET FETCH는 정렬된 결과의 앞부분을 건너뛴 뒤 지정한 행 수를 반환하는 페이징 방식이다. 페이지 번호를 직접 이동할 수 있다는 장점이 있지만, 깊은 페이지에서는 반환하지 않을 행까지 정렬 순서대로 확인하고 버려야 한다.예를 들어 페이지 크기가 50행일 때 10,000번째 페이지는 논리적으로 앞선 499,950행을 건너뛴 후 50행을 반환한다. 적절한 인덱스가 있어 정렬 연산을 피하더라도 OFFSET 자체가 사라지는 것은 아니다. 이 과정에서 인덱스 페이지 접근과 논리 읽기가 누적되며 동시 요청이 많으면 버퍼 풀 압박과 CPU 사용량 증가로 이어진다.대용량 테이블에서의 대체 원칙은 명확하다. 임의의 페이지..
[MySQL] OFFSET 100000 지연 원인과 복합 키셋 페이징 전환 방법
OFFSET 페이징: 실무적 정의와 운영상 중요성MySQL에서 OFFSET 페이징은 정렬된 결과의 앞부분을 건너뛴 뒤 지정한 행 수만 반환하는 방식이다. LIMIT 20 OFFSET 100000은 100001번째 행으로 즉시 이동하는 명령이 아니다. MySQL은 정렬 순서에 맞는 선행 100000행을 확인하고 버린 뒤 다음 20행을 반환해야 한다.인덱스를 사용하더라도 건너뛸 행을 탐색하는 비용은 사라지지 않는다. 페이지가 뒤로 갈수록 스캔하는 인덱스 레코드와 CPU 사용량이 증가하며, 필요한 컬럼을 인덱스가 포함하지 않으면 테이블 접근까지 반복될 수 있다. 동시 요청이 집중되는 운영 환경에서는 버퍼 풀 경쟁과 디스크 I/O 병목으로 이어진다.OFFSET 100000 이후의 목록 조회는 마지막 행의 정렬 ..
[MSSQL] Sort 메모리 부족과 TempDB Spill 진단: Memory Grant 문제 구분 방법
Sort 연산자: 실무적 정의와 운영상 중요성MSSQL에서 Sort 연산자는 입력 행을 ORDER BY, GROUP BY, DISTINCT, 윈도 함수 또는 조인 처리에 필요한 순서로 재배열한다. 정렬 대상이 메모리 안에 들어오면 작업은 메모리에서 끝나지만, 확보한 작업 공간보다 데이터가 커지면 일부 정렬 데이터를 TempDB에 기록한다. 이 현상이 TempDB Spill이다.Spill 여부와 Memory Grant 부족은 같은 의미가 아니다. Spill은 실제 실행 중 메모리가 부족했다는 결과이고, Memory Grant 문제는 왜 부족해졌는지를 설명하는 원인이다. DBA는 실제 실행 계획의 Sort 경고를 먼저 확인한 뒤 메모리 요청량, 실제 부여량, 최대 사용량, 카디널리티 오차를 순서대로 대조해야..
[MySQL] ORDER BY와 LIMIT의 filesort를 제거하는 정렬 인덱스 설계
ORDER BY와 LIMIT: 실무적 정의와 운영상 중요성MySQL에서 ORDER BY와 LIMIT는 정렬된 결과 중 일부 행만 반환하는 목록 조회의 핵심 구문이다. 관리 화면, 게시물 목록, 주문 이력처럼 최신 데이터 몇 건을 조회하는 기능에서 반복적으로 사용된다.대량 테이블에서 가장 중요한 판단 기준은 정렬 결과를 만든 뒤 LIMIT을 적용하는지, 정렬된 인덱스를 읽다가 필요한 행 수에서 중단하는지이다. 전자는 실행 계획의 Extra에 Using filesort가 나타날 수 있으며, 후보 행이 많으면 CPU 사용량과 메모리 소비, 임시 파일 I/O를 유발한다. 후자는 적절한 복합 인덱스를 순서대로 읽으므로 정렬 작업 자체를 생략할 수 있다.필터·정렬 컬럼의 기본 순서는 명확하다. WHERE절의 동등 ..
[MSSQL] AUTO_UPDATE_STATISTICS 임계값과 대량 적재 후 오래된 통계 진단
AUTO_UPDATE_STATISTICS: 실무적 정의와 운영상 중요성SQL Server의 AUTO_UPDATE_STATISTICS는 데이터 변경량을 추적하고, 옵티마이저가 오래되었다고 판단한 통계를 쿼리 컴파일 과정에서 갱신하는 데이터베이스 옵션이다. INSERT, UPDATE, DELETE, MERGE로 데이터 분포가 변하면 수정 횟수가 누적되지만, 변경 직후 모든 통계가 즉시 갱신되는 구조는 아니다.자동 갱신 여부는 통계별 수정 카운터와 임계값으로 결정된다. 임계값을 넘은 통계도 해당 통계를 참조하는 쿼리가 컴파일되거나 캐시된 실행 계획을 실행하기 전까지 실제 갱신이 지연될 수 있다. 따라서 대량 적재가 끝났다는 사실만으로 통계가 이미 최신 상태라고 판단하면 안 된다.오래된 통계는 실제 행 수와 예..
[MySQL] 히스토그램 통계로 편향 컬럼의 행 수 추정치를 교정하는 방법
MySQL 히스토그램: 실무적 정의와 운영상 중요성MySQL에서 히스토그램(Histogram)은 컬럼 값의 분포를 버킷 단위로 저장하는 옵티마이저 통계이다. 특히 인덱스가 없는 편향 컬럼의 조건절 선택도(Selectivity)를 추정할 때 사용된다. 동일한 값이 균등하게 분포한다고 가정하기 어려운 상태 코드, 지역, 등급, 처리 상태 컬럼이 대표적인 대상이다.독자가 확인하려는 핵심은 히스토그램이 행 수 추정치를 얼마나 개선하는가이다. 정해진 개선 비율은 없다. 개선 폭은 데이터 편향도, 조건값의 빈도, 버킷 수, 샘플링 비율과 통계 최신성에 따라 달라진다. 따라서 생성 전후의 추정 행 수를 실제 행 수와 비교하여 오차 배수로 판단해야 한다.히스토그램은 인덱스를 생성하지 않는다. 조건 컬럼에 인덱스가 없다..