* MSSQL 실행 순서 : 쿼리문 -> 컴파일 -> 통계정보 -> 실행계획 -> Seek(OLTP) or Scan(OLAP) 실행
* WHERE 첫 번째 조건은 무조건 "=" 조건이 되도록
. SARG 조건
. WHERE 구문에 맞게 Index 생성 (오름차순, 내림차순도 동일하게 적용)
. 사용자 정의 함수 X
. 로컬 변수, 로컬 테이블 X (SP 파라미터로 적용 : SP에서 SP 호출 방식 적용)
. OLTP : Hash Match 나오는 경우 튜닝 해야 함
. OLAP : Hash Match (대용량, Index 사용 못함)
7장. 고급 쿼리 튜닝
. JOIN
- Nested Loop Join (OLTP성 조인)
- Hash Match Join, Merge Join (OLAP성 조인)
- 외부 입력이 먼저 실행되고 내부 입력이 다음에 실행 된다
- 2개의 테이블 중 선택도가 좋은 지에 따라 "외부 입력" 지정 (인덱스 사용 가능, select 되는 행 수가 적은 테이블)
- "내부 입력"은 반드시 인덱스 사용 가능 (Index Seek)
- "외부 입력" --> "검색 테이블" (선택도 좋아야 함)
- "내부 입력" --> "조인 테이블" (인덱스 조인)
- 조인 시 "내부 입력" 테이블의 컬럼은 변형하지 말아야 한다 (반드시 Index Seek 해야 성능이 좋아진다)
- 집합 연산자는 거의 대부분이 중복 제거 된다고 생각하면 된다
- JOIN 시 한번에 2 테이블 씩 처리 (예 10개 테이블 10! = 3,628,800 가지)
. join 테이블이 많을 수록 성능 저하의 요인 (실행 계획 수립 과정 적정?한 선택)
* (핵심) 초기 테이블의 외부, 내부 입력 선정
* 조인 분리 : 임시 테이블 사용 고려
* 비정규화 고려
. OUTER JOIN
- 불필요한 OUTER JOIN 사용하지 말자
. Hash Match Join ("외부 입력", "내부 입력" 그대로 유지)
- 인덱스 유무 확인 필요
. Merge Join
- 데이터가 "정렬"되어 있어야 한다
- 클러스터 인덱스가 있어야 한다 또는 커버링 인덱스가 있어야 한다
- Sort 하고 Merge 처리 : Sort Merge (가끔씩 발생)
. Adaptive Join (적응형 조인)
- 실행 계획에 "논리적 연산 : 내부 조인" 표시
- 실행 계획에 재사용 부작용 --> 쿼리 분리 처리 (옵티마이저에서 자동 처리)
- OPTION(USE HINT(...))
. Semi Join 과 Anti Semi Join
- Semi Join (교집합)
. WHERE aaa in (selesct aaa from ...)
- Anti Semi Join (차집합)
. WHERE aaa not in (selesct aaa from ...)
. 모델링에서 고려해야 함
. 가장 어려운 튜닝 조건
8장. Hint
. Join Hint
- INNER {...} JOIN : 왼쪽 테이블이 "외부 입력"
- OPTION (... JOIN)
- 반드시 필요한 경우 사용
- 사용 시 왜 사용하는 지에 대한 주석으로 설명을 추가 한다
9장. Subquery
(예)
- and exists (select * from ....)
- and 중분류 = (select top 1 중분류 from ....)
. Join <--> Group by
- Group by 먼저 해야 할 경우는 조인(집계)열의 밀도가 높은 경우
- join (....) b on a.aa = b.bb : (....) 안에 있는 쿼리는 a.aa = b.bb 조건을 내부적으로 미리 적용된다
. ROW_NUMBER()
- 페이징 쿼리에 많이 사용
- ver 2012 이상 : ORDER BY ... DESC OFFSET ... ROWS FETCH NEXT .. ROWS ONLY (사용 권장)
- 검색 조건별 인덱스 생성해서 사용하는 것이 좋음
- 첫번째 페이징 정적 쿼리문 작성, 이후 페이지는 동적 쿼리문 작성 (예)
. 차집합 구하기 (참조)
- nullif() 함수 : null 값 활용 : select 1 / 0 <-- nullif()
(예)
. ISNULL(E_PLAYER_NAME,'HELLOWORLD') ISNULL값, /*E_PLAYER_NAME이 널이면 HELLOWORLD 출력*/
. NULLIF(TEAM_ID,'K10') K10이면NULL, /*TEAM_ID가 K10이면 NULL*/
. COALESCE(E_PLAYER_NAME,NICKNAME) /*널 아닌 최초값 출력*/
. OLTP 기분 병렬 쿼리
- 병렬 처리 퀴리는 OLAP성 쿼리
- 병렬 처리 퀴리 2개 이상의 CPU를 사용한다
- OPTION (MAXDOP 0) : CPU 사용수 (0 --> 병렬 전체 사용, 1 --> 직렬 처리, 4 --> 병렬 최대 4개)
. STRING_AGG (...) : "1,2,4,7,4,5,7,,...." 문자열 만드는 함수
- ver 2017 이상
. 함수
- 실제 실행 계획에서 "QueryTimeStats" 속성 아래 "UdfCpuTime", "UdfElapsedTime" 속성 참조
- ver 2019 이상 함수 쿼리가 자동으로 튜닝 처리 해준다. (Scalar UDF InLine 옵션 적용 시)
- "인라인 스칼라 Tsql Udf 포험 : True"
- STRING_SPLIT() : ver 2016 이상
10장. 저장 프로시저 튜닝
. 권장 세션 옵션
- SET LOCK_TIMEOUT
- SET NOCOUNT ON
- SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
. sp_ 접두사는 금기
11장. 성능 문제 및 튜닝 방안
. OPTION (RECOMPILE)
. OPTION (OPTIMIZE FOR (@aaa {'값'}))