전체쿼리 결과 집합을 쉼 없이 연속적으로 전송하지 않고 사용자로 부터 Fetch Call이 있을때 마다 일정량씩 나누어 전송하는 것을 '부분범위 처리'라고 한다.

 

정렬조건이 있을때 부분범위 처리

인덱스는 항상 정렬된 상태를 유지하므로 전체 데이터를 정렬하지 않고도 정렬된 상태의 결과집합을 바로 전송할 수 있다.

 

Array Size 조정을 통한 Fetch Call 최소화

대량 데이터를 파일로 내려받는다면 데이터를 모두 전송해야하므로 가급적 Array Size를 크게 설정해야한다. Array Size를 조정한다고 해서 전송해야 할 총량이 변하진 않지만, Fetch Call 횟수를 그만큼 줄일수 있으며, 반대로 앞쪽 일부 데이터만 Fetch하다가 멈추는 프로그램이라고 할 경우 Array Size를 작게 설정하는 것이 유리하다.(불필요하게 많은 데이터를 전송하고 버리는 비효율을 줄일수 있음.)

 

쿼리 툴에서 부분범위 처리

모든 DBMS는 데이터를 조금씩 나눠서 전송한다. 즉, 부분범위 처리 방식으로 결과집합을 전송한다. 이 특징을 이용해 중간에 멈췄다가 사용자의 추가 요청이 있을 때마다 데이터를 가져오도록 구현하고 안하고의 차이는 책의 저자가 말하길 DBMS 클라이언트 프로그램을 개발하는 개발자의 몫이라고 말한다.

 

부분범위 처리 구현

개발 프레임워크에 미리 부분범위 처리 된 구현 기능을 활용하면 된다고 한다. 

 

OLTP(Online Transaction Processing) 

온라인 트랜잭션을 처리하는 프로그램을 말하며, 일반적으로 소량 데이터를 읽고 갱신한다. (하지만 항상 소량 데이터만 조회하는것은 아님)

수천수만 건을 조회하는 경우에는 많은 테이블 랜덤 액세스가 발생하기  때문에 제 성능을 내기 어려울수 있다. 버퍼캐시히트율이 좋다면 빠른 성능을 보일수 있지만, 아닌 경우도 존재하기 때문이다. 

 그러나 OLTP성 업무에서 쿼리 집합이 아주 많을 때 사용자가 모든 데이터를 일일이 다 확인하지 않는다. 특정한 정렬 순서로 상위 일부 데이터만 확인한다. (ex. 은행계좌 입출금 조회, 뉴스 또는 게시판 등등..) 주로 목록을 조회하는 경우. 이런 경우 항상 정렬 상태를 유지하는 인덱스를 이용하면, 정렬 작업을 생략하고 앞쪽 일부 데이터를 아주 바르게 보여줄수 있다. (인덱스와 부분범위 처리를 잘 활용한다면 OLTP환경에서 극적인 성능 개선 효과를 얻을수 있다고 함.)

 

멈출 수 있어야 의미있는 부분범위 처리(문제는 앞쪽 일부만 출력하고 멈출 수 있는가..? _부분범위 처리 핵심*)

해당 내용은 추후 5장 3절에서  다룬다고 함..

 

배치I/O  :  읽는 블록마다 건건이 I/O Call을 발생시키는 비효율을 줄이기 위해 고안한 기능.

  인덱스를 이용해 테이블을 액세스하다가 버퍼 캐시에서 블록을 찾지 못하면 일반적으로 디스크 블록을 바로 읽는데(오라클11g 까지), 배치I/O기능이 작동하면 테이블 블록에 대한 디스크 I/O Call을 미뤘다가 읽을 블록이 일정량 쌓이면 한꺼번에 처리한다. (오라클12c 이후 해당)

(* 12c에 도입된 일반 배치 I/O와 NL조인에 작동하는 기존 배치I/O는 파라미터, 힌트, 실행계획 표현방식이 모두 다르다.)

 

 배치I/O를 통해 얻을수 있는 성능 이점이 많은에도 불구하고 시스템레벨에서 이를 비활성화 하는 경우가 종종있다. 이 기능을 비활성화하는 이유는 '필요한' order by를 생략한 SQL패턴 때문라고 한다. SQL에 order by가 없으면 결과 집합의 정렬 순서를 보장할 필요가 없으므로

옵티마이저가 배치I/O를 선택할 수 있고, 출력된 결과집합의 정렬 순서가 매번 다를수 있다.

 

데이터 정렬 이슈 :

배치I/O 기능이 작동하면 인덱스를 이용해서 출력하는 데이터 정렬 순서가 매번 다를수 있다는 사실에 주목해야 함..

 

 

 

 

오라클에서 랜덤 엑세스가 아예 발생하지 않도록 테이블을 인덱스 구조로 생성하는 방법을 IOT(Index-Organized Table)이라 함.

(MS-SQL Server 에서는 '클러스터형 Clustered 인덱스'라고 함. 

 테이블을 찾아가기 위한 ROWID를 갖는 일반 인덱스와 달리 IOT는 그자리에 테이블 데이터를 갖는다.(즉, 테이블 블록에 있어야 할 데이터를 인덱스 리프 블록에 모두 저장하고 있다. IOT에서는 '인덱스 리프 블록이 곧 데이터 블록' 이다. )

 

일반 테이블은 '힙 구조 테이블'이라고 부른다.  일반 힙 구조 테이블에 데이터를 입력할 때는 랜덤 방식을 사용한다. 반면, IOT는 인덱스 구조 테이블이므로 정렬 상태를 유지하며 데이터를 입력한다.

 

IOT는 인위적으로 클러스터링 팩터를 좋게 만드는 방법 중 하나이며, Between이나 부등호 조건으로 넓은 범위를 읽을때 유리하다. 또한, 데이터 입력과 조회 패턴이 서로 다른 테이블에도 유용하다.


클러스터 테이블 : 클러스터 테이블에는 인덱스 클러스터와 해시 클러스터 두 가지가 있다.

인덱스 클러스터 테이블 :

 클러스터 키값이 같은 레코드를 한 블록에 모아서 저장하는 구조. 한 블록에 모두 담을 수 없을 때는 새로운 블록을 할당해서 클러스터 체인으로 연결한다. 추가적으로 여러 테이블 레코드를 같은 블록에 저장할 수도 있는데, 이를 '다중 테이블 클러스터' 라고 함. (일반 테이블은 하나의 데이터 블록을 여러 테이블이 공유할 수 없음)

 

 클러스터에 테이블을 담기 전에 아래와 같이 클러스터 인덱스를 반드시 정의해야 한다. 클러스터 인덱스는 데이터 검색 용도로 사용할 뿐만 아니라 데이터가 저장될 위치를 찾을 때도 사용하기 때문..

 클러스터 인덱스도 일반 B*Tree 인덱스 구조를 사용하지만,  테이블 레코드를 일일이 가리키지 않고 해당 키 값을 저장하는 첫 번째 데이터 블록을 가르킨다는 점이 다르다. 따라서 클러스터 인덱스의 키값은 항상 유니크하다(=중복값이 없다)

 

해시 클러스터 테이블 :

 해시 클러스터는 인덱스를 사용하지 않고 해시 알고리즘을 사용해 클러스터를 찾아간다는 점만 다르다. 

온라임 프로그래밍 튜닝 vs 배치 프로그래밍 튜닝

_온라인 프로그래밍 튜닝은 보통 소량 데이터를 읽고 갱신 하므로, 인덱스를 효과적으로 활용하는 것이 중요. 조인도 대부분 NL 방식을 사용 NL조인은 인덱스를 이용하는 조인 방식 (온라인 환경에서 대량 데이터를 조회 할 때도 아주 빠른 응답 속도를 낼수 있다 )

 

_배치 프로그래밍 튜닝 항상 전체범위 처리 기준으로 튜닝해야 한다.  처리대상 집합 중 일부를 빠르게 처리하는 것이 아니라 전체를 빠르게 처리하는 것을 목표. 이럴때는 Full scan과 해시 조인이 유리함

 

** 초대용량 테이블을 full scan 하면 상당히 오래 기다려야 하므로, 배치 프로그램에서는 파티셔닝 활용 전량이 매우 중요한 튜닝요소, 이 책의 저자는 모든 성능 문제를 인덱스로 해결 하려 하면 안되며, 인덱스는 다양한 튜닝 도구 중 하나일 뿐 이라고 한다.

 

*NL조인, 해시조인 참고 url https://mozi.tistory.com/222

 

[DATABASE] 조인 수행 원리란? NL, Sort Merge, Hash 조인이란?

NL Join 프로그래밍에서 사용하는 중첩된 반복문과 유사한 방식으로 조인을 수행합니다. 선행 테이블의 조건을 만족하는 행을 추출하여 후행 테이블을 읽으면서 조인을 수행합니다. 이 작업은 선

mozi.tistory.com

 

3.1.4 인덱스 컬럼 추가

테이블 액세스 최소화를 위해 가장 일반적으로 사용하는 튜닝 기법은 인덱스에 컬럼을 추가하는 것이다. 

> 인덱스에 컬럼을 추가 할 경우 인덱스 스캔량은 줄지 않지만, 테이블 랜덤 액세스 횟수를 줄여줄수 있다.

 

인덱스 클러스터링 팩터 효과 확인
클러스터링 팩터가 좋은 인덱스를 이용하면, 테이블 액세스량에 비해 블록I/O가 훨씬 적게 발생한다.

 

3.1.5 인덱스만 읽고 처리

비효율이 없더라도 인덱스 스캔 과정에서 얻은 데이터가 많다면 그만큼 테이블 랜덤 액세스가 많이 발생하므로 성능이 느릴 수 밖에 없다.

이런 경우일때 반드시 성능을 개선해야 한다면, 쿼리에 사용된 컬럼을 모두 인덱스에 추가해서 테이블 액세스가 아예 발생하지 않게 하는 방법을 고려해 볼 수 있다. 이 방법이 효과는 매우 좋을수 있지만, 추가해야 할 컬럼이 많아 실제 적용하기 곤란한 경우가 많다고 한다.

[+] 인덱스만 읽어서 처리하는 쿼리를 'Covered 쿼리'라 부르며, 쿼리에 사용한 인덱스를 'Covered 인덱스'라고 부른다.

 

Include 인덱스 ( SQL Server 2005 버전에 추가된 유용한 기능 )

인덱스 키 외에 미리 지정한 컬럼을 리프 레벨에 함께 저장하는 기능. 인덱스를 생성할 때 include 옵션을 지정하면 된다. 컬럼은 최대 1,023개 까지 지정할 수 있다. include 인덱스는 순전히 테이블 랜덤 액세스를 줄이는 용도로 개발됐다.

 

3.1 테이블 액세스 최소화

 

- 테이블 랜덤 액세스 

 

인덱스를 스캔하는 이유는, 검색 조건을 만족하는 소량의 데이터를 인덱스에서 빨리 찾고 거기서 테이블 레코드를 찾아가기 위한 주소값, 즉 ROWID를 얻으려는데 있다.

(ROWID는 물리적 주소보다 논리적 주소에 가깝다고 볼수있다고 한다. 추가적으로 정리하자면, 디스크 상에서 테이블 레코드를 찾아가기 위한 위치 정보를 담기 때문..)

 

_ 메인 메모리DB와 비교

디스크를 경유하지 않고 대부분 데이터를 메모리에서 읽음. (메인 메모리 DB만큼 빠르지는 않다.)

인스턴스를 기동하면 디스크에 저장된 데이터를 버퍼캐시로 로딩하고 이어서 인덱스를 생성한다. 메모리상의 주소정보, 즉 포인터를 갖는다. 따라서 인덱스를 경유해 테이블을 액세스하는 비용이 오라클과 비교할수 없을정도로 낮다고 한다.

 

_ I/O 매커니즘복습

DBA(= 데이터파일번호 + 블록번호)는 디스크 상에서 블록을 찾기 위한 주소 정보이다.

I/O 성능을 높이려면 버퍼캐시를 활용해야 한다. 해싱 알고리즘으로 버퍼 헤더를 찾고, 거기서 얻은 포인터로 버퍼 블록을 찾는다.

 인덱스로 테이블 블록을 액세스할 때는 리프 블록에서 읽은 ROWID를 분해해서 DBA정보를 얻고, 테이블을 Full Scan 할 때는 익스텐트 맵을 통해 읽을 블록들의 DBA 정보를 얻는다. 

 

* 인덱스 ROWID는 포인터가 아니다! ( 디스크 상에서 테이블 레코드를 찾아가기 위한 논리적인 주소 정보!!!)

 

_ 인덱스 ROWID는 우편주소

 

- 인덱스 클러스터링 팩터

 클러스터링 팩터(Clustering Factor, 이하 'CF')는 군집성 계수로 변역할 수 있는 용어로 [ 특정 컬럼을 기준으로 같은 값을 갖는 데이터가 서로 모여있는 정도를 의미함.]

_CF가 좋은 컬럼에 생성한 인덱스는 검색 효율이 매우 좋다.

 

// 인덱스 클러스터링 팩터 효과

CF가 좋은 컬럼에 생성한 인덱스가 검색 효율이 좋다는것은, 테이블 액세스량에 비해 블록I/O가 적게 발생함을 의미한다. (추후 설명보충)

 

- 인덱스 손익분기점

인덱스 ROWID를 이용한 테이블 액세스는 생각보다 고비용 구조. 따라서, 읽어야 할 데이터가 일정량을 넘는 순간, 테이블 전체를 스캔하는(Full Scan)보다 오히려 더 느려진다. 이 느려지는 지점을 흔히 '인덱스 손익분기점' 이라고 한다.

 

인덱스를 이용한 테이블 액세스가 Table Full Scan보다 느려지게 만드는 가장 핵심적인 두가지 요인은 아래와 같다.

1. Table Full Scan은 시퀀셜 액세스인 반면, 인덱스 ROWID를 이용한 테이블 액세스는 랜덤 액세스 방식

2. Table Full Scan은 Multiblock I/O인 반면, 인덱스 ROWID를 이용한 테이블 액세스는 Single Block I/O방식.

 

위 와 같은 요인에 의해 인덱스 손익분기점은 보통 5~20% 낮은 수준에서 결정된다. CF가 나쁘면 손익 분기점은 5% 미만에서 결정되며, 심할때는 (BCHR이 매우 안 좋을때) 1% 미만으로 낮아진다. 반대로 CF가 아주 좋을때는 손익분기점이 90% 수준까지 올라가기도 한다.

 

* 인덱스 손익분기점과 버퍼캐시 히트율

인덱스를 스캔하면서 테이블을 액세스하다 보면 어느 순간부터 대부분 테이블 블록을 캐시에서 찾게된다. 

만 건만 넘어도 시퀀셜 액세스와 Multiblock I/O방식, 즉 Table Full Scan 방식으로 읽는게 빠를 수 있다.

 

주의) 저자가 말하길 인덱스가 항상 좋을수 없음을 설명하려고 손익분기점이란 개념을 사용했을뿐, 이를 높이기 위해 어떤 조치를 해야 한다는 뜻으로 오해하지 말길 바라며, 테이블 스캔이 항상 나쁜것은 아니며, 반대로 인덱스 스캔이 항상 좋은 것도 아니라는 사시을 설명하는데 목적이 있다고 한다. 

 

- Index Range Scan

> B*Tree 인덱스의 가장 일반적이고 정상적인 형태의 액세스 방식, 

인덱스 루트에서 리프 블록까지 수직적으로 탐색한 후에 '필요한 범위만' 스캔한다.

 

* 인덱스를 Range Scan 하려면 선두 컬럼을 가공하지 않은 상태로 조건절에 사용해야 한다. 반대로 말하면, 선두 컬럼을 가공하지 않은 상태로 조건절에 사용하면 Index Range Scan은 무조건 가능하다. 

 

- Index Full Scan

> 수직적 탐색없이 인덱스 리프 블록을 처음부터 끝까지 수평적으로 탐색하는 방식

대게 데이터 검색을 위한 최적의 인덱스가 없을 때 차선으로 선택

 

- Index Unique Scan

> 수직적 탐색만으로 데이터를 찾는 스캔 방식으로서, Unique 인덱스를 '=' 조건으로 탐색하는 경우에 작동

Unique 인덱스가 존재하는 컬럼은 중복 값이 입력되지 않게 DBMS가 데이터 정합성을 관리 해 준다.

 

- Index Skip Scan

인덱스 선두 컬럼을 조건절에 사용하지 않으면 옵티마이저는 기본적으로 Table Full Scan을 선택한다. Table Full Scan 보다 I/O를 줄일 수 있거나 정렬된 결과를 쉽게 얻을 수 있다면, Index Full Scan을 사용하기도 함.

> 조건절에 빠진 인덱스 선두 컬럼의 distinct Value 개수가 적고 후행 컬럼의 distinct Value 개수가 많을 때 유용하다. 

 Index Skip Scan 은 루트 또는 브랜치 블록에서 읽은 컬럼 값 정보를 이용해 조건절에 부합하는 레코드를 포함할 '가능성이 있는' 리프 블록만 골라서 액세스 하는 스캔 방식.

 

- Index Fast Full Scan

Index Fast Full Scan이 Index Full Scan보다 빠른 이유는, 논리적인 인덱스 트리 구조를 무시하고 인덱스 세그먼트 전체를 Mulitblock I/O 방식으로 스캔하기 때문이다. 

 Index Fast Full Scan은 Mulitblock I/O방식을 사용하므로 디스크로부터 대량의 인덱스 볼록을 읽어야 할 때 큰효과를 발휘한다. 속도는 빠르지만, 인덱스 리프 노드가 갖는 연결 리스트 구조를 무시한 채 데이터를 읽기 때문에 결과집합이 인덱스 키 순서대로 정렬되지 않는다. 

 Index Range Scan 또는 Index Full Scan과 달리, 인덱스 파티션 돼 있지 않더라도 병렬 쿼리가 가능한 것도 중요한 특징중 하나다.

병렬 쿼리 시에는 Direct Path I/O 방식을 사용하기 때문에 I/O 속도가 더 빨라진다. 

 

- Index Range Scan Descending 

Index Range Scan과 기본적으로 동일한 스캔 방식이다. 인덱스를 뒤에서 부터 앞쪽으로 스캔하기 때문에 내림차순으로 정렬된 정렬된 결과집합을 얻는다는 점만 다르다. 

 

 

 

 

 

1.3.5 논리적I/O vs 물리적I/O

논리적 블록 I/O는 sql문을 처리하는 과정에서 메모리 버퍼캐시에서 발생한 총 블록 I/O

물리적 블록 I/O는 디스크에서 발생한 총 블록 I/O

메모리I/O는 전기적 신호인데 반해, 디스크I/O는 액세스 암(arm)을 통해 물리적 작용이 일어나므로 메모리 I/O에 비해 상당히 느림 (보통 10,000)배 느리며, 디스크 경합이 심할 때는 더 느리다.

 

버퍼캐시 히트율 : 버퍼캐시 효율을 측정하는데 전통적으로 가장 많이 사용해 온 지표

BCHR = ( 캐시에서 곧바로 찾은 블록수 / 총 읽은 블록 수 ) x 100

           = ( ( 논리적 I/O - 물리적 I/O ) / 논리적 I/O ) x 100

           = ( 1 - ( 물리적 I/O ) / ( 논리적 I/O ) ) x 100

 

tip. BCHR은 읽은 전체 블록 중에서물리적인 디스크I/O를 수반하지 않고 곧바로 메모리에서 찾은 비율을 나타낸다고 볼수있다고한다.

* 실제 SQL 성능을 향상하려면 물리적I/O가 아닌 논리적I/O를 줄여한다는 사실을 알수있음.

 - 논리적 I/O를 줄이는 방법으로는 SQL을 튜닝해서 읽는 총 블록 개수를줄이면 됨. (당연한 이야기...)

 

1.3.6 Single Block I/O vs Multi Block I/O

 메모리 캐시가 클수록 좋지만, 데이터를 모두 캐시에 적재할수는 없다. ( 비용적한계, 기술적한계 때문에..) 그리하여 일부만 캐시에 적재해서 읽을수 있는데.

한번에 한 블록씩 요청해서 메모리에 적재하는 방식이 'Single block I/O' 이며, 한 번에 여러 블록씩 요청해서 메모리에 적재하는 방식을 'Multi block I/O'라고 한다.

 - 인덱스를 이용 할때는 기본적으로 인덱스와 테이블 블록 모두 Single block I/O 방식을 사용한다.

 - 반대로, 많은 데이터 블록을 읽을 때는 Multiblock I/O 방식이 효율적이며, 인덱스를 이용하지않고 테이블 전체 스캔을 할때 사용한다.

 

1.3.7 Table Full Scan vs Index Range Scan

테이블 전체를 스캔해서 읽는방식, 인덱스를 이용해서 읽는 방식 2가지로 테이블에 저장된 데이터를 읽는방식이 존재한다.

( 많은 개발자의 인식과 달리 인덱스가 sql 성능을 떨어뜨리는 경우도 상당히 많다는 점도 알아야한다고 함 ex.집계용 sql과 배치 프로그램)

 

1.3.8 캐시 탐색 메커니즘

Direct Path I/O를 제외한 모든 블록 I/O는 메모리 버퍼캐시를 경유한다. 아래 오퍼레이션은 모두 버퍼캐시 탐색과정을 거친다.

- 인덱스 루트 블록 읽을때

- 인덱스 루트 블록에서 얻은 주소 정보로 브랜치 블록을 읽을 때

- 인덱스 브랜치 블록에서 얻은 주소 정보로 리프 블록을 읽을때

- 인덱스 리프 블록에서 얻은 주소 정보로 테이블 블록을 읽을때

- 테이블 블록을 Full Scan 할때

 

공유캐시의 특정 자원을 두 개 이상 프로세스가 같이 사용할수없다, 같이 사용하는것 처럼 보이지만, 특정 순간에는 한 프로세스만 사용 할수있다. 그 순간 다른 프로세스는 줄 서서 기다려야 한다. 이런 줄서기가 가능하도록 지원하는 메커니즘이 래치(Latch)다.

위 설명을 이해하기 위해 서적에서는 카쉐어링 서비스로 예를 들었다( ex. 쏘카, 그린카) 

 

추가개념_

버퍼 Lock :  버퍼블록의 자체에 대한 직렬화 문제를 해결

1.2 SQL 공유 및 재사용

1.2.1 소프트파싱VS하드파싱

라이브러리 캐시(Library Cache) :

sql파싱, 최적화, 로우소스생성 과정을 거쳐 생성한 내부 프로시저를 반복 재사용할수있도록 캐싱해두는 메모리공간

- SGA(System Global Area) 서버프로세스와 백그라운드 프로세스가 공통으로 액세스하는 데이터와 제어구조를 캐싱하는 메모리공간

 

소프트파싱(Soft Parsing) : SQL을 캐시에서 찾아 곧바로 실행단계로 넘어감

하드파싱(Hard Parsing) : SQL을 캐시에서 찾는데 실패하여 최적화 및 로우소스 생성단계까지 모두 거치는것

 

옵티마이저가 SQL을 최적화할때 사용하는 정보 종류

- 테이블, 컬럼,  인덱스 구조에 관한 기본 정보

- 오브젝트 통계 :  테이블 통계, 인덱스 통계, (히스토그램을 포함한)칼럼 통계

- 시스템 통계 :  CPU속도,  Single Block I/O 속도, Multiblock I/O 속도 등

- 옵티마이저 관련 파라미터

 

1.2.2 바인드 변수의 중요성

이름없는 SQL문제

sql 자체가 이름이기 때문에 텍스트 중 작은 부분이라도 수정되면 그 순간 다른 객체가 새로 탄생하는구조

일회성 또는 무효화된 sql까지 모두 저장하려면 많은공간이 필요하고, 그만큼 sql을 찾는속도가 느려진다(sql영구저장안하는이유)

*sql텍스트가 변하면 sql id도 변한다

 

공유가능 SQL

동일한 sql 쿼리를 반복하게되면 내부 처리 루틴은 모두 같을것이다.

그렇다면, sql쿼리 조건문에 해당되는 파라미터를 처리하는 프로시저 하나를 공유하면서 재사용하는것이 유리할것

파라미터 Driven 방식으로 sql을 작성하는 방법이 제공되는데 이것이 바로 바인드 변수다.

 

1.3 데이터 저장 구조 및 I/O 메커니즘

1.3.1 I/O = SLEEP (os또는 I/O서브시스템이 I/O를 처리하는 동안 프로세스는 잠을 자기 때문에..)

 

1.3.2 데이터베이스 저장 구조

데이터를 저장하라면 *테이블스페이스를 생성해야한다. (테이블스페이스 : 세그먼트를 담는 컨테이너로서, 여러개의 데이터 파일로 구성)

테이블 스페이스를 생성했으면, *세그먼트를 생성한다. 세그먼트는 테이블, 인덱스처럼 데이터 저장공간이 필요한 오브젝트이다.

(테이블, 인덱스를 생성할때 데이터를 어떤 테이블스페이스에 저장할지를 지정한다.)

세그먼트는 여러 *익스텐트로 구성됨, 파티션 구조가 아니라면 테이블도 하나의 세그먼트, 인덱스도 하나의 세그먼트가 된다. LOB컬럼은 그 자체가 하나의 세그먼트를 구성하므로 자신이 속한 테이블과 다른 별도 공간에 값을 저장한다. (익스텐트는 공간을 확장하는 단위) 

 테이블이나 인덱스에 데이터를 입력하다가 공간이 부족해지면 해당 오브젝트가 속한 테이블스페이스로부터 익스텐트를 추가로 할당받음

 익스텐트는 역속된 블록들의 집합이기도 한다. 익스텐트 단위로 공간을 확장하지만,  사용자가 입력한 레코드를 실제로 저장하는 공간은 데이터 블록이다. ( != DB2, SQL서버 같은 DBMS는 페이지page 라는 용어사용)

 즉,  한 블록에 저장된 레코드는 모두 같은 테이블 레코드이다 :) 다중 테이블 클러스터일 때는 한 블록에 여러 테이블 레코드가 같이 저장

 

데이터베이스 저장 구조 용어정리 -

블록 :  데이터를 읽고 쓰는 단위

익스텐트 : 공간을 확장하는 단위, 연속된 블록 집합

세그먼트 : 데이터 저장공간이 필요한 오브젝트(테이블, 인덱스, 파티션, LOB등)

테이블스페이스 : 세그먼트를 담는 컨테이너

데이터파일 : 디스크 상의 물리적인 OS파일

 

+ DBA(Data Block Address)

: 모든 데이터 블록은 디스크 상에서 몇 번 데이터파일의 몇 번째 블록인지를 나타내는 자신의 고유 주소값을 가짐.

 

1.3.3 블록 단위 I/O

오라클은 기본적으로 8KB 크기의 블록을 사용하므로 1Byte를 읽기 위해서 8KB를 읽는 셈

(오라클은 2KB, 4KB 16KB 크기 블록을 사용할 수도 있다. MS SQL은 8KB 단일 사이즈 블록만 지원)

 

1.3.4 시퀀셜 액세스 VS 랜덤 액세스

테이블 또는 인덱스 블록을 읽는 방식으로는 2가지 방식이 있다

시퀀셜(Sequential) 액세스 : 논리적 또는 물리적으로 연결된 순서에 따라 차례대로 블록을 읽는 방식

오라클은 세그먼트에 할당된 익스텐트 목록을 세그먼트 헤더에 맵으로 관리하여 테이블 블록간의 서로 논리적인 연결고리를 시퀀셜 방식

으로 액세스하게 한다.

 

- 읽어야 할 익스텐트 목록을 익스텐트 맵에서 얻고, 각 익스텐트의 첫 번째 블록 뒤에 연속해서 저장된 블록을 순서대로 읽는것이 FullTableScan 이다. 

 

랜덤(Random) 액세스 :  논리적, 물리적인 순서를 따르지 않고, 레코드 하나를 읽기 위해 한 블록씩 접근하는 방식

SQL 처리 과정과 I/O

1.1 SQL 파싱과 최적화

1.1.1 SQL(Structured Query Language)은 구조적(structured)이고 집합적(set-based)이고

선언적(declarative)인 질의 언어

 

1.1.2 SQL최적화 :

DBMS 내부에서 프로시저를 작성하고 컴파일하여 실행 가능한 상태로 만드는 전 과정

#sql최적화 과정

1. sql파싱 (파싱트리생성, Syntax체크, Semantic체크)

2. SQL최적화

3. 로우 소스 생성

 

1.1.3 SQL옵티마이저( LIKE 자동차 네비게이션 ):

사용자가 원하는 작업을 가장 효율적으로 수행할수있는 최적의 데이터 액세스 경로를 선택해주는 DBMS의 핵심 엔진

 

1.1.4 sql실행계획의 비용(cost)는 어디까지나 예상치

 

1.1.5 옵티마이저 힌트: 

개발자가 직접 더 효율적인 액세스 경로를 찾아낼수도 있음, 이럴 때 옵티마이저 힌트를 이용해 액세스 경로를 바꿀수 있음

* 옵티마이저 힌트 주의사항:

힌트안 인자 나열할땐 콤마사용 가능하나, 힌트와 힌트사이에는 사용하면 안됨, 테이블 지정할 때 스키마 명까지 명시하면 안됨, from절 테이블명에 alias를 지정햇다면, 힌트에도 반드시 alias를 사용해야 한다.(alias 사용 안할시 그 힌트는 무시됨)

(옵티마이저 힌트 사용방법: 주석 기호에 '+'를 붙이면 됨)

 

 

 

 feat. 친절한SQL튜닝  

 

+ Recent posts