Post

SQL 처리 과정과 I/O

#naver-import

원문: https://blog.naver.com/qoxmfaktmxj/222861817512

SQL : Structured Query Language

프로시저를 만들어 내는 DBMS(DataBase Management System) 내부 엔진이 SQL 옵티마이저이다. (DBMS의 두뇌 = DBMS는 SQL전달받아 Parsing함)

사용자 --SQL--> 옵티마이저 --실행계획--> 프로시저

DBMS 내부에서 프로시저를 작성하고 Compile 하여 실행 가능한 상태로 만드는 전 과정을 SQL 최적화라고 한다.

1.SQL 최적화

1)SQL 파싱

사용자 --SQL--> 옵티마이저

SQL을 날릴 때 SQL Parser가 파싱을 진행한다.

-1.SQL문을 이루는 개별 구성 요소를 분석해 파싱 트리를 생성한다

-2.Syntax 체크(문법체크)한다

-3.Semantic체크(의미상 오류를 체크)한다.ex)없는 테이블,컬럼 등

이후 SQL 최적화를 시작한다

2)SQL 최적화

이때 Optimizer가 일하게 된다.

가장 효과적인 경로로 실행계획을 구성한다. -->DB 성능을 결정하는 핵심 엔진이라고 볼 수 있다.

[실행계획을 구성 : 로우 소스 생성(Optimizer가 선택한 실행경로를 실제 실행 가능한 코드 또는 Procedure 형태로 포맷팅 한다.)]


옵티마이저는 비용기반과 규칙기반이 있다.

규칙기반은 여러 가치 규칙을 기준으로 옵티마이저를 실행하며 Oracle 8 이전에 쓰였다.

(Rule Based Optimizer : RBO)

비용기반은 실질적으로 소모되는 시간을 계산하는 방식이다.

비용 기반 Optimizer는 Query 수행 시 실행계획을 찾아 예상비용을 산정 후 최소 비용을 선택하는 방식이다. - 실행계획을 확인해 실행계획을 강제한다.

(Cost Based Optimizer : CBO)

ex) 우리가 흔히 쓰는 Navigation

실행 시 옵티마이저 힌트를 우선 체크한다.

select /* + INDEX(A 고객_PK)*/ * from 고객 A where 고객ID=‘xxxx’; /*+*/대신 --+ 가능한데 개발 환경에 따라 주석 처리 가능성이 있기 때문에 쓰지 말 것

힌트와 힌트 사이에는 콤마(,) 사용 시 맨 앞에만 적용된다.(인자 사이는 가능)

/*+INDEX(A A_X01) INDEX(B, BX_03)*/ -> 모두 유효

/*+INDEX(C), FULL(D)*/ -> 첫번째 힌트만 유효

테이블 지정 시 스키마명 사용하지 않고, ALIAS 지정 시 꼭 사용한다.

(ex.owner.emp같이 사용 안함, select * from emp E : E 사용)

SQL 파싱

=>라이브러리 캐시에 존재 => 실행(소프트 파싱)

=>라이브러리 캐시에 존재 x => 최적화 => 로우 소스 생성 => 실행(하드 파싱)

ex)*라이브러리 캐시 : V$SQL

SQL이 느린 이유?

대부분 I/O 때문이다. (디스크 I/O)

데이터 베이스 <==I/O Channel== Storage

I/O 병목 발생

I/O = SLEEP ? OS 또는 I/O 서브시스템이 I/O를 처리하는 동안 프로세스는 잠을 잔다.

*DataBase 저장 구조

Table Space 를 생성 -> Segment를 생성한다.

Segment란 Table INDEX처럼 저장 공간이 필요한 Object다

여기서 Block은 데이터를 읽고 쓰는 단위이며 Rowid가 존재한다.

이를 ERD 표기로 나타내어 보면

( O: 0개 I: 1개 <- 여러 개)

Data I/O 단위가 block이므로 특정 record를 하나만 알고 싶어도 해당 블록을 통째로 읽게 된다.

ex) Show parameter block_size, v$parameter (name: db_block_size)

Index Leaf block은 앞 뒤를 가리키는 주소값으로 논리적으로 서로 연결되어 있다.

Table이나 Index block을 읽는 방식은

첫번째. 순서대로 읽는 방식 Sequential access

두번째. 랜덤 Random access

*테이블 블록 간에는 서로 논리적인 연결고리가 없다

->Oracle에서는 Segment에 할당된 extent목록을 segment Header에 map으로 관리한다.

extent map은 각 extent의 첫번째 블록 주소 값을 갖는다.

Segment 공간이 부족해지면 Table space로부터 추가로 extent를 할당 받는다.

segment에 할당된 extent는 모두 같은 데이터 파일에 위치하지 않을 수 있다.

->하나의 tablespace를 여러 데이터 파일로 구성 시 파일 경합을 줄일 수 있기 때문이다.

정리하자면

1.블록에 데이터를 저장

2.블록만으로는 관리가 힘듬 (몇 십만 블록 관리, 한개 테이블 내에 분산되어 존재하기 때문)

3.블록 집합 인스턴트 도입

-> 익스텐트의 첫 위치와 블록 갯수로 데이터 관리

-> 데이터 한번에 읽어오니 Full scan 성능 향상

4.table이나 index등 데이터 한번 더 모은 extent집합 -> segment도입

댓글