데이터베이스/친절한 SQL 튜닝
SELECT-LIST 컬럼 가공시 정렬연산 수행 확인 및 개선방법
인덱스가 Id, ch_date, ch_order 순으로 생성되어 있을 경우 MIN 값을 구해도 별도의 정렬연산을 수행하지 않는다. 수직적 탐색을 통해서 가장 왼쪽지점에서 보는 최소 값이 바로 구하고자 하는 값이기 때문이다. 1SELECT MIN(ch_date) FROM scott.SORT_TEST WHERE ID = ‘C’;csMAX의 경우도 마찬가지이다. MIN과 다른 점은 왼쪽에서 찾는게 아니라 가장 오른쪽에 있는 데이터를 찾는다는 점이다.1SELECT MAX(ch_date) FROM scott.SORT_TEST WHERE ID = ‘C’;cs 그래서 두 개의 실행계획을 살펴보면 인덱스 리프 블록의 왼쪽(MIN) 또는 오른쪽 (MAX)에서 레코드 하나(FIRST ROW)만 읽고 멈춘다.1SELECT ..
인덱스를 이용한 sort 연산 생략
인덱스 Range Scan이 가능하려면 가공하려는 컬럼의 데이터가 정렬되어 있어야 가능하다. 인덱스는 그렇기 때문에 정렬이 되어있다. 그래서 인덱스를 사용하는 이유가 있다. 테이블 생성1234create table sort_test (id char,ch_date date,ch_order varchar(10));cs 제약조건 추가1ALTER TABLE SCOTT.SORT_TEST ADD CONSTRAINT ODER_PRIMARY PRIMARY KEY (ID,CH_DATE,CH_ORDER);cs 데이터 실행계획PK를 기준으로 알아서 정렬이 되어있다. ( ID -> CH_DATE -> CH_ORDER 순서대로) 만약 별도로 order by를 sql에 지정한다고 해도 옵티마이저는 sort order by를 진행..
인덱스 Range Scan이 되기 위한 선행 조건
인덱스 Range Scan이 되기 위한 선행 조건 학교이름, 나이, 이름, 주소로 구성된 테이블이 있다고 가정해보자. 빠른 검색을 위해서 인덱스를 학교 이름, 나이, 이름으로 구성해서 만들었다고 가정해보자. CREATE INDEX SCOTT.student_idx ON SCOTT.STUDENT_TEST ("SCHOOL_NAME" ASC,"AGE" ASC,"NAME" ASC); 인덱스 구성의 순서로 인해 학교순으로 정렬하고, 나이로 정렬하고, 이름으로 정렬해서 데이터를 찾는다. 그렇기 때문에 이름을 조건으로 데이터를 검색하였을 때 결국 모든 리프노드를 다 검색해야한다. 그렇기 때문에 인덱스를 Range Scan 하기 위한 가장 첫 번째 조건은 인덱스 선두 컬럼이 조건절에 있어야한다. 그렇다면 만약 인덱스에 ..
인덱스 기본 사용법과 인덱스 스캔이 불가능한 경우 소
우리가 색인을 통해 단어를 찾는 순간을 생각해보자. ㄱ. 가나가방 장식가시 방석ㄴ.나방 나방 나무누에고치나무 장식누나 여기서 누에고치라는 단어를 찾을 때, 위에서 순차적으로 진행한다고 가정하였을 때 큰 어려움 없이 발견할 수있다. 이 방식을 Index Range Scan이라고 한다.반대로 장식이 포함된 단어를 찾아보자. 찾기 어려운 건 아니여도 모든 색인을 전부 확인해봐야한다. 이렇게 모든 색인을 다 확인하고 나서 찾을 수 있는 방식을 Index Full Scan 방식이라고 한다.그렇기 때문에 인덱스의 기준이되는 데이터 즉 컬럼을 가공하게되면 Range Scan이 불가능해진다. 정리하면 인덱스 기준이 가공되면 인덱스 스캔의 시작점을 찾는 수직적 탐색이 불가능해지기 때문이다. 몇 가지 쿼리를 예로 들어보자..
인덱스 구조 및 탐색
SQL 튜닝에서 사용되는 인덱스 인덱스 구조는 수평적 탐색과 수직적 탐색을 이룬다. 이것을 이해하고 나면 인덱스 구조에 대해 그림이 명확해진다. 인덱스를 우리가 중심적을 공부하는 이유는 SQL 튜닝에 초점이 맞쳐져있다. SQL 튜닝을 통해 원하고자 하는 데이터를 빠르게 얻기 위해서 인덱스에 대해 공부하는데 SQL을 사용하여 데이터를 찾는 방법은 이미 많이 알려진 두 가지 방식이 있다. 테이블 전체 스캔 인덱스를 이용 그럼 Table Full Scan 방식이 아닌 인덱스를 사용하기 위해 적절 한 튜닝의 핵심요소가 무엇인지 살펴보자. 만약 몸무게가 기재되어있는 학생 연명부가 있다고 가정해보자. 학생명과 몸무게로 정렬되어 있을때 학생을 찾기 위한 과정에서 학생을 찾고 몸무게 검색하는 과정이 거친다. 이런과정을..
오라클 SGA 캐시 탐색 메커니즘 정리
Direct Path I/O를 제외한 모든 블록 I/O는 메모리 버퍼캐시를 경유한다. 버퍼캐시의 구조는 해시 구조로 관리된다. 해시 함수를 통해서 나온 결과를 사용하여 해시체인(Bucket)을 찾고 그 해시체인에 연결되어 있는 버퍼 정보를 사용하여 버퍼 캐시 정보를 찾아 갈 수 있다. 만약 해시체인을 찾아주는 해시 알고리즘이 mod(x, 5)라고 할 때, 25번째 블록을 찾고 싶은 경우 해시함수를 사용해서 5로 나누고 나온 나머지 0이 해시체인 0번째를 의미한다. 그 해시체인에는 버퍼 헤더들이 들어있다. 25라는 버퍼헤더를 찾고 그 버퍼헤더가 가리키고 있는 버퍼 블록을 접근하여 데이터를 탐색하면 된다. 만약 27번째 블록을 읽으려고 해시함수를 거쳐서 2번째 해시체인에 갔으나, 버퍼 헤더 27이 없다면??..
오라클의 Table Full Scan과 Index Range Scan
테이블에 저장된 데이터를 읽는 방식은 두 가지이다. Table Full Scan은 해당 테이블에 전체 블록을 읽어서 사용자가 원하는 데이터를 찾는 방식이다. 그리고 Index Range Scan은 인덱스를 이용하여 데이터를 일정부분읽어서 ROWID로 테이블 레코드를 찾아가는 방식이다. ROWID는 테이블 레코드가 디스크 상에 어디 저장됐는지를 가리키는 위치 정보이다. 상당수의 툴(Toad, Orange)에서 데이터를 Full Scan 하는 경우에 실행계획에서 빨간색으로 경고를 보여준다. 그래서 Table Full Scan에 경우 더 느리다는 고정관념이 있으나 모두 그런것은 아니다. Index를 이용한 스캔방식이 더 느린 경우도 있다. Table Full Scan에 경우 읽고자 하는 데이터의 블록을 Mul..
Single Block I/O와 Multi Block I/O
캐시 모두 데이터를 적재해두면 속도도 빠르고 좋으나, 메모리에 한계가 있기 때문에 항상 적재하고 있을수는 없다. 그래서 캐시에서 찾지 못한 경우 I/O 콜을 사용하여 블록씩 데이터를 읽어들이는데 한번에 한 블록씩 가지고 오는 것을 Single Block I/O라고 한다. 그리고 여러 블록을 한번에 가지고 오는 것을 Multi Block I/O라고 한다. 기본적인 인덱스와 테이블 블록을 읽어들일때는 Single Block I/O 방식이 사용된다. 하지만 대량의 데이터를 테이블에서 가지고와야 할 때는 Multiblock I/O가 좋고 그 단위가 크면 대량의 블록에서 데이터를 한번에 가지고 올 수 있기에 프로세스가 잠자는 횟수를 줄일 수 있어 좋다. 그렇기 때문에 대용량 데이터를 Full Scan할때 Mult..
오라클의 논리적 I/O와 물리적 I/O의 차이 그리고 버퍼 캐시 히트율(BCHR) 구하기
오라클에서 SQL을 파싱하는 것을 내부에 저장하고 있는 라이브러리 캐시와 데이터를 캐시하고 있는 DB 버퍼캐시가 존재한다. 이 데이터를 저장하고 있는 캐시 또한 SGA의 중요한 요소 중 하나이다. 데이터 블록에 대해 캐시를 해두어서 다음번에 읽어들일때 같은 작업을 반복해서 하지 않도록 하는 기능을 제공한다. 그럼 이런 버퍼 캐시를 이용하여 처리하는 방식과 직접 디스크에 접근하여 데이터를 접근하는 방식에 차이는 무엇인지 알아보자. 논리적 I/O 와 물리적 I/O 오라클에서 SQL 문장을 처리하는 과정에는 두 가지 I/O가 존재한다. 하나는 논리적 블록 I/O 나머지는 물리적 블록 I/O이다. 논리적 I/O는 SQL 문장을 처리하는 과정에서 메모리 버퍼캐시에서 발생한 총 블록 I/O로써 메모리에 접근하여 데..
시퀀셜 액세스와 랜덤 액세스
데이터베이스에서 데이터를 블록단위로 읽는다. 1 ~ 3 byte와 같이 작은 데이터를 읽을때도 하나의 블록을 읽어들인다. 그리고 테이블뿐만 아니라 인덱스도 블록단위로 읽어들인다. 데이터베이스의 총 블록 사이즈를 알고 싶으면 다음 쿼리를 통해 확인해 볼 수있다.1select value from v$parameter where name = 'db_block_size';cs 그럼 테이블과 인덱스를 블록단위로 읽는 방식에 대해서 알아보자. 테이블 또는 인덱스를 읽는 방식 시퀀셜 액세스 (Sequential Access)논리적 또는 물리적으로 연결된 순서에 따라 차례대로 블록을 읽어들이는 방식이다. 인덱스 리프블록은 앞뒤를 가리키는 주소값으로 서로 연결되어 있는데 이를 이용하여 순차적으로 스캔하는 방식이다.테이블..