Chap 2. SQL 문장의 실행 원리

- SQL 문장 실행의 전체적인 순서는 Parse (구문분석) -> Bind (값 치환) -> Execute (실행) -> Fetch (인출) 이다. (Select 문 기준)


 1. Select 문장의 실행 원리 


1) Parse (구문분석)

- 사용자가 SQL 문장을 실행하면, 아래의 순서로 구문분석을 하게 된다. 

Step1 - Syntax check (문법 검사)

키워드 검사라고도 하며, Oracle 에서 미리 정해놓은 키워드 부분을 검사한다. (Select, From, where 등등)


Step2 - Semantic Check (의미 검사)

테이블 이름, 컬럼 이름처럼 사용자 마다 다른 부분을 검사한다. 


Step3 - 권한 검사 

권한이 있는지 없는지를 검사한다. 


Step4 - 실행 계획 생성

위의 권한 검사까지 다 완료 되었다면, Shared Pool 이라는 곳의 Library Cache 를 검사해서 해당 SQL 문장이 이미 실행된 적이 있는지를 검사해서 실행 계획을 세운다. 이 과정을 좀 더 상세히 설명하자면, 

* SQL 문장을 ASCII 값 (숫자값) 으로 변경 후, 해당 숫자 값을 Hash 함수를 통해 특정 Hash value 를 얻는다. 

* 이렇게 해서 얻은 Hash value 값과 Shared Pool 의 Library Cache 에 있는 Hash value 들과 비교를 해서 동일한 값이 있는지 확인을 한다. (이런 Hash Value 들이 들어가 있는 곳을 Hash Bucket 이라고 한다.)

* Hash Bucket 을 읽어서 동일한 Hash Value 가 있다면, 이제 실제 내용을 찾아야 하는데, 실제 내용이 있는 곳을 커서 (Cursor) 라고 한다. Library Cache 안에 있는 커서를 공유커서라고 하는데, 주의할 사항은 같은 SQL 문장이라 하더라도 사용자가 다르거나 한다면, 다른 내용이라고 여겨져서 커서를 공유할 수 없다. 

* 즉, 실행 계획을 세울 때 이렇게 Library Cache 안에서 원하는 SQL 문과 실행 계획이 들어 있는 커서를 찾아야 하는데,  Library Cache 에는 아주 많은 SQL 문장과 실행 계획이 들어가기 때문에 일일히 실제 커서를 방문해서 해당 내용이 있는지 없는지를 검사하지는 못한다. 그래서 Oracle 에서는 어떤 커서에 어떤 데이터가 들어있는지를 List 를 통해서 관리하게 되는데 이걸 Hash List 라고 부른다. 결론적으로, Library Cache 안에서 원하는 SQL 문과 실행 계획이 들어 있는 커서를 찾기 위해서는 반드시 Hash List 를 읽어야 한다. 

============> 여기 까지의 과정을 Soft parse 또는, 커서 공유를 한다고 한다. Soft parse 의 장점은 SQL 수행 속도가 빨라진다는 데에 있다. 하지만 문제는, Hash List 는 1개 밖에 없기 때문에 여러명의 사용자가 SQL문을 수행 했을 경우, 동시에 이 List 를 읽으려면 문제가 발생 할 수 있다. 그래서 Library Cache 의 Hash List 를 순서대로 보기 위해서 Oracle 에서는 Library Cache Latch 를 가지게끔 정하고 있다. (순번표 같은...)


* 만약 원하는 실행 계획을 Hash List 에서 찾지 못한다면 (Soft parse 에서 실패한다면), 새로운 실행계획을 세워야 하는데, Oracle 에서는 이런 역활을 하는 것이 옵티마이져(Optimizer) 이다. Optimizer 는 Data Dictionary 를 참고해서 실행 계획을 생성한다. 

============> 이 단계를 Hard parse 라고 한다. 


2) Bind (값 치환)

- Parsing 작업 (구문분석) 이 끝나면 Bind 단계로 넘어가는데 이 단계를 예를 들어보면, 

- emp 테이블에서 사원 번호를 입력받아 100 명의 사원 정보를 출력 한다고 하면, 사원번호 값만 다르고 SQL 문장은 동일할 것이다. 이럴 경우, 100 개의 SQL 을 Parsing 해서 100 개의 실행 계획을 만드는 것 보다 1번만 parsing 해서 1 개의 실행 계획을 만들어서 사원번호만 바꿔서 100번 실행하는 것이 수행 속도가 훨씬 빠르다. 

- 이런 작업을 Bind 라 하며, 여기서 사용되어지는 사원번호를 Bind 변수라고 한다. 


3) Execute (실행)

- Parse 와 Bind 단계를 거친 후에 서버 프로세스는 해당 데이터를 가져오기 위해 Database Buffer Cache 를 먼저 확인한다. (Chap 1 의 SGA 구성요소 참고 - 사용자가 조회하거나 변경하려는 모든 데이터는 Database Buffer Cache 에 있어야 한다.) 

- 만약 원하는 데이터 블록이 Buffer cache 에 있다면 바로 다음 단계인 Fetch 를 진행하게 되고, 데이터 블록이 없다면 하드 디스크에서 필요한 블록을 찾아서 메모리 즉, Database buffer cache 로 복사해 온다. 

- 이런 과정을 Execute 라고 한다. 


4) Fetch (인출)

- Execute 단계 까지 완료 되면, 원하는 데이터 블록이 메모리 (Database buffer cache) 에 있게 될 것이다. 이 블록에서 사용자가 원하는 데이터만 골라내는 과정이 Fetch 이다. 


 2. Update 문장의 실행 원리  

- Select 문장과 1~3 단계인 parse -> bind -> execute 단계 까지는 동일하고 (fetch 단계는 없다), execute 단계에서 조금 다른 부분이 있다. 

- Execute 단계에서 원하는 데이터가 들어있는 블록을 Database buffer cache 로 가져 온 후 변경되는 데이터의 변경 내역을 Redo log buffer 에 먼저 기록한다. 

- 그 후에 Undo Segment 에 원본 이미지를 기록 한 후 Database buffer cache 의 내용을 변경한다. 

- Oracle 에서는 이렇게 데이터가 변경되는 것을 트랜잭션 (Transaction) 이라고 한다.

by 짱구를꼭말려 2013. 9. 8. 13:12