[SQL] SQL 파싱과 최적화
![[SQL] SQL 파싱과 최적화](/assets/img/database/sql/logo_upscale.png)
옵티마이저가 SQL을 어떻게 처리하는지, 서버 프로세스는 데이터를 어떻게 읽고 저장하는지 알아봅니다.
1. SQL이란?
SQL
은 ‘Structured Query Language’의 줄임말로 구조적 질의 언어라는 뜻입니다.
SQL은 기본적으로 구조적(structured)이고 집합적(set-based)이고 선언적(declarative)인 질의 언어입니다.
원하는 결과 집합을 구조적, 집합적으로 선언하지만 그 결과집합을 만드는 과정은 절차적일 수밖에 없습니다. 이러한 과정을 수행하는 것이 DBMS 내부 엔진인 SQL 옵티마이저
입니다.
DBMS 내부에서 프로시저를 작성하고 컴파일해서 실행 가능한 상태로 만드는 전 과정을 SQL 최적화
라고 합니다.
2. SQL 최적화
SQL 최적화는 다음과 같은 과정을 거칩니다.
- SQL 파싱: 사용자로부터 SQL을 전달받으면 가장 먼저 SQL 파서(Parser)가 파싱을 진행합니다. SQL 문을 이루는 개별 구성요소를 분석해 파싱 트리를 생성합니다. 이 때 문법적 오류나 의미적 오류가 없는지 확인합니다.
- SQL 최적화: 옵티마이저가 다양한 실행 경로를 생성해 비교한 후 가장 효율적인 하나를 선택합니다.
- 로우 소스 생성: 옵티마이저가 선택한 실행경로를 실제 실행 가능한 코드 또는 프로시저 형태로 포매팅합니다.
3. SQL 옵티마이저
SQL을 최적화 하는 과정에서 옵티마이저가 많은 역할을 수행하였습니다. 그렇다면 옵티마이저란 무엇일까요?
옵티마이저는 사용자가 원하는 작업을 가장 효율적으로 수행할 수 있는 최적의 데이터 액세스 경로를 선택해 주는 DBMS의 핵심 엔진입니다.
4. 옵티마이저의 최적화 단계
이러한 옵티마이저의 최적화 단계는 다음과 같습니다.
- 사용자로부터 전달받은 쿼리를 수행하는 데 후보군이 될 만한 실행계획들을 찾아냅니다.
- 데이터 딕셔너리에 미리 수집해 둔 오브젝트 통계 및 시스템 통계정보를 이용해 각 실행계획의 예상비용을 산정합니다.
- 최저 비용을 나타내는 실행계획을 선택합니다.
5. 실행계획과 비용
DBMS의 SQL 실행경로 미리보기 기능을 통해 SQL 옵티마이저가 생성한 트리구조로 표현한 처리 절차를 사용자가 확인할 수 있으며, 이를 실행계획이라 합니다. 자신이 작성한 SQL이 테이블을 스캔하는지 인덱스를 스캔하는지, 인덱스를 스캔한다면 어떤 인덱스를 스캔하는지 등을 확인할 수 있고, 예상과 다른 방식으로 처리된다면 실행경로를 변경할 수 있습니다.
옵티마이저는 비용을 근거로 실행 계획을 선택합니다. 비용이란 쿼리를 수행하는 동안 발생할 것으로 예상하는 I/O 횟수 또는 예상 소요시간을 표현한 값입니다. 이러한 비용은 어디까지나 예상치이기 때문에 실제 수행할 때 발생하는 I/O 또는 시간과 차이가 있을 수 있습니다.
6. 옵티마이저 힌트
옵티마이저는 보편적으로 좋은 선택을 하지만, 항상 최선은 아닙니다. 옵티마이저는 완벽하지 않기 때문에 SQL이 복잡할수록 실수할 가능성이 큽니다. 사용자는 데이터 또는 업무 특성을 활용해 더 효율적인 액세스 경로를 찾아낼 수도 있습니다.
이러한 힌트는 다음과 같이 사용합니다.
SELECT /*+ INDEX(인덱스명) */
어트리뷰트1, 어트리뷰트2, …
FROM 테이블명
WHERE 어트리뷰트3 = ‘n’
/*+ */와 같이 주석 기호에 ‘+’를 붙이는 방법을 통해 사용할 수 있습니다.
7. 옵티마이저 힌트 사용의 주의사항
힌트를 사용할 때 몇 가지 주의사항이 있습니다.
- 힌트 안에 인자를 나열할 땐 ‘,’를 사용할 수 있지만, 힌트와 힌트 사이에 사용하면 안됩니다.
/*+ INDEX(A A_XO1) INDEX(B, B_X03) */ 와 같은 힌트는 두 표현 모두 사용할 수 있습니다.
하지만 /*+ INDEX(C), FULL(D) */ 와 같은 힌트의 경우 첫 번째 힌트만 유효하고 FULL(D)의 경우 무효됩니다. - 테이블을 지정할 때 스키마명까지 명시하면 안됩니다.
SELECT /*+ FULL(SCOTT.EMP) */
FROM EMP
위와 같은 힌트의 경우 무효됩니다. - FROM절 테이블명 옆에 ALIAS를 지정했다면, 힌트에도 반드시 ALIAS를 사용해야 합니다.
SELECT /*+ FULL(EMP) */
FROM EMP E
위와 같은 힌트의 경우 FROM절에서 ALIAS를 지정했지만 힌트에서는 테이블명을 사용했기 때문에 무효됩니다.