전체 글

전체 글

    [MSSQL] 비클러스터드 인덱스의 Index Seek와 Table Scan 손익분기점 분석

    비클러스터드 인덱스: 실무적 정의와 운영상 중요성MSSQL에서 비클러스터드 인덱스(Nonclustered Index)는 인덱스 키와 행 위치 정보로 구성된 별도 B-Tree 구조이다. 검색 조건의 선택도(Selectivity)가 높으면 필요한 키 범위만 탐색하는 Index Seek가 효율적이다. 그러나 인덱스에 없는 컬럼까지 반환하면 원본 행을 다시 찾는 Key Lookup 또는 RID Lookup이 추가된다.반환 행이 증가하면 Seek 비용은 일정하게 유지되지 않는다. 인덱스 탐색 이후 각 행에 대한 Lookup과 데이터 페이지 접근이 반복되기 때문이다. 반면 Table Scan은 힙(Heap)의 데이터 페이지를 처음부터 끝까지 순차적으로 읽으며, 읽어야 할 전체 페이지 수를 기준으로 비용이 형성된다...

    [MySQL] 낮은 선택도 인덱스에서 Full Table Scan을 선택하는 기준과 검증 방법

    낮은 선택도 인덱스: 실무적 정의와 운영상 중요성MySQL에서 인덱스가 존재한다는 사실은 해당 인덱스가 항상 사용된다는 의미가 아니다. 옵티마이저는 후보 실행 계획별 비용을 계산하고, 인덱스 접근보다 전체 테이블 스캔(Full Table Scan)의 예상 비용이 낮으면 type=ALL을 선택한다.선택도(Selectivity)는 조건이 전체 행 중 얼마나 적은 행을 반환하는지를 나타낸다. 실무에서는 조건 일치 행 수 ÷ 전체 행 수로 반환 비율을 계산하며, 반환 비율이 낮을수록 선택도가 높다고 표현한다. 서로 다른 값의 수를 의미하는 카디널리티(Cardinality)와 선택도는 관련되지만 동일한 지표는 아니다.예를 들어 상태 컬럼에 값이 세 종류만 존재해도 특정 값이 전체의 극소수라면 그 조건은 높은 선택..

    [MSSQL] DMV로 미사용·중복 인덱스를 판별하는 방법: user_seeks 해석과 삭제 기준

    MSSQL 미사용·중복 인덱스 DMV: 실무적 정의와 운영상 중요성MSSQL에서 sys.dm_db_index_usage_stats는 인덱스별 사용자 조회와 갱신 활동을 누적해서 보여 주는 동적 관리 뷰(DMV)이다. user_seeks, user_scans, user_lookups, user_updates와 각 작업의 마지막 수행 시각을 확인할 수 있다.user_seeks가 낮다는 사실만으로 인덱스를 삭제하면 안 된다. 이 값은 인덱스의 필요성을 평가한 결과가 아니라 현재 DMV 관찰 구간에서 Seek 연산이 기록된 횟수이다. SQL Server 재시작 이후에 실행되지 않은 월말 배치, 장애 대응 쿼리, 분기별 정산, 특정 파라미터 구간의 조회는 수치에 반영되지 않을 수 있다.또한 인덱스는 Seek 외에..

    [MySQL] Invisible Index로 중복 인덱스 삭제 전 영향 범위를 검증하는 절차

    Invisible Index: 실무적 정의와 운영상 중요성MySQL에서 Invisible Index는 인덱스 구조와 유지 작업은 그대로 보존하면서 옵티마이저의 일반적인 실행 계획 후보에서만 제외하는 기능이다. 인덱스를 즉시 DROP하지 않고도 해당 인덱스가 사라진 상황을 먼저 검증할 수 있다. 중복 인덱스 정리 과정에서 복구 시간이 긴 재생성 작업을 피할 수 있다는 점이 핵심이다.Invisible 상태에서도 INSERT, UPDATE, DELETE가 발생하면 인덱스 엔트리는 계속 갱신된다. 따라서 쓰기 비용과 저장 공간은 감소하지 않는다. 이 기능은 삭제 효과를 측정하는 수단이 아니라, 읽기 쿼리의 실행 계획 회귀와 의존 범위를 검증하는 안전장치이다.검증 순서는 삭제 후보 선정, 기준 실행 계획 저장, ..

    [MSSQL] INCLUDE 컬럼 설계로 Key Lookup 병목을 제거하는 판단 기준

    INCLUDE 컬럼: 실무적 정의와 운영상 중요성MSSQL에서 Key Lookup은 비클러스터형 인덱스(Nonclustered Index)에서 검색 조건을 만족하는 행을 찾은 뒤, SELECT에 필요한 나머지 컬럼을 가져오기 위해 클러스터형 인덱스에 다시 접근하는 연산이다. Heap 테이블에서는 같은 목적의 RID Lookup이 발생한다. 검색 행마다 반복되는 임의 페이지 접근이므로 반환 행이 증가할수록 논리 읽기와 CPU 사용량이 함께 증가한다.INCLUDE 컬럼은 비클러스터형 인덱스의 리프 레벨에 조회용 컬럼을 저장한다. 검색 키 순서에는 참여하지 않지만 쿼리에 필요한 컬럼을 인덱스 내부에서 모두 반환할 수 있게 한다. 이 상태를 커버링 인덱스(Covering Index)라고 하며, 적절히 설계하면 ..

    [MySQL] 커버링 인덱스 설계: 테이블 접근 제거 조건과 과도한 인덱스 비용

    커버링 인덱스: 실무적 정의와 운영상 중요성MySQL에서 커버링 인덱스(Covering Index)는 쿼리가 요구하는 컬럼을 하나의 인덱스에서 모두 읽을 수 있도록 설계한 인덱스이다. 검색 조건만 인덱스에 존재하는 것으로는 충분하지 않다. SELECT, WHERE, JOIN, ORDER BY, GROUP BY 처리에 필요한 컬럼이 인덱스만으로 해결되어야 테이블 레코드 접근을 제거할 수 있다.InnoDB의 보조 인덱스 리프에는 보조 인덱스 키와 기본 키(Primary Key)가 저장된다. 따라서 기본 키 컬럼은 보조 인덱스 정의에 직접 나열하지 않아도 커버링에 이용될 수 있다. 반면 인덱스에 없는 일반 컬럼을 SELECT하면 보조 인덱스에서 기본 키를 찾은 뒤 클러스터드 인덱스를 다시 탐색해야 한다.커버링..

    [MSSQL] 복합 인덱스 선행 컬럼 누락이 Index Scan을 만드는 이유와 키 순서 설계

    복합 인덱스 키 순서: 실무적 정의와 운영상 중요성MSSQL의 복합 인덱스(Composite Index)는 둘 이상의 컬럼을 하나의 키로 구성한 B-Tree 인덱스이다. INDEX (CustomerID, OrderDate)는 CustomerID를 먼저 정렬하고, CustomerID가 같은 행 내부에서 OrderDate를 정렬한다.따라서 전체 인덱스가 OrderDate 순서로 정렬된 것은 아니다. 첫 번째 키인 CustomerID가 조건절에서 빠지면 SQL Server는 특정 OrderDate가 존재할 연속 범위의 시작점과 종료점을 계산할 수 없다. 이 경우 옵티마이저는 후행 키 조건을 만족하는 행을 찾기 위해 인덱스 리프 페이지를 넓게 읽는 Index Scan을 선택할 수 있다.핵심은 WHERE 절에 조..

    [MySQL] 복합 인덱스 컬럼 순서: 등가 조건을 앞에, 범위 조건을 뒤에 배치하는 원칙

    복합 인덱스 컬럼 순서: 실무적 정의와 운영상 중요성MySQL에서 복합 인덱스(Composite Index)는 둘 이상의 컬럼 값을 지정된 순서로 정렬해 저장하는 B-Tree 인덱스이다. WHERE 절에 등가 조건과 범위 조건이 함께 있다면 일반적인 배치 원칙은 등가 조건 컬럼을 앞에 두고, 실제 탐색 범위를 결정할 범위 조건 컬럼을 그 뒤에 두는 것이다.예를 들어 tenant_id = ?, status = ?, created_at >= ?가 함께 사용된다면 기본 후보는 (tenant_id, status, created_at)이다. 선행 등가 조건으로 탐색할 인덱스 구간을 고정한 다음, 해당 구간 안에서 날짜 범위를 연속적으로 읽을 수 있기 때문이다.다만 이를 모든 쿼리에 적용되는 절대 규칙으로 이해하면..

    [MSSQL] Actual Execution Plan의 Estimated Rows 오차 원인과 카디널리티 교정 절차

    Actual Execution Plan: 실무적 정의와 운영상 중요성MSSQL의 Actual Execution Plan은 옵티마이저가 컴파일 시점에 선택한 계획과 실행 중 수집된 행 수 정보를 함께 보여 주는 진단 자료이다. Estimated Number of Rows는 통계와 카디널리티 추정 모델을 이용한 예상값이며, Actual Number of Rows는 해당 실행에서 연산자가 반환한 행 수이다.두 값의 차이는 단순한 표시 오차가 아니다. 옵티마이저는 예상 행 수를 기준으로 인덱스 접근 방식, 조인 순서, Nested Loops·Hash Match·Merge Join 선택, 병렬 처리 여부와 메모리 그랜트(Memory Grant)를 결정한다. 따라서 하위 연산자의 작은 추정 오류가 상위 조인과 정렬..

    [MySQL] EXPLAIN ANALYZE 카디널리티 오차 진단과 실행 계획 튜닝 순서

    EXPLAIN ANALYZE: 실무적 정의와 운영상 중요성MySQL에서 EXPLAIN은 옵티마이저가 쿼리를 실행하기 전에 계산한 예상 실행 계획을 반환한다. 반면 EXPLAIN ANALYZE는 쿼리를 실제로 실행한 뒤 각 iterator의 소요 시간, 반환 행 수, 반복 횟수를 예상값과 함께 표시한다.추정 행 수와 실제 처리 행 수가 다를 때 가장 먼저 확인할 항목은 전체 실행 시간이 아니다. 실행 계획의 하위 노드부터 estimated rows와 actual rows가 처음 크게 벌어지는 지점을 찾아야 한다. 상위 조인 노드의 오차는 하위 테이블 접근 단계에서 발생한 카디널리티 오류가 누적된 결과일 가능성이 높다.카디널리티 추정이 틀리면 옵티마이저는 잘못된 인덱스, 조인 순서, Nested Loop 반..