Background Image
기타
2009.08.15 03:43

CUBRID 스캔 이해하기

조회 수 15113 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

CUBRID 스캔 이해하기

소개: CUBRID에 적용된 스캔의 개념, 종류 및 동작 원리, 종류 및 관련 예제를 기술한다.

적용 대상: CUBRID2008

 

스캔의 개념

사전적 의미

스캔의 개념

Scan

━타

1. …을 자세히 조사하다, 정밀 검사하다; …을 눈여겨보다, 유심히 보다.

2. 〔신문·책 따위〕를 대충 훑어보다, 급히 읽다.

━자

1. 시의 운율을 살피다, 시행을 운각으로 나누다; (시행이) 운율에 맞다, 운각으로 나누어지다.

2. TV(영상이) 주사하다.

━명

1. 정밀 검사, 음미; 눈여겨보기.

2. 대충[급히] 읽기.

스캔이란?

새로운 프로젝트가 시작되면서 우리 회사의 김 대리는 내일 회의에서 발표할 개발 시스템에 관한 도표를 찾느라 정신 없이 바쁩니다. 해당 도표가 문서에 있다는 건 아는데, 정확하게 어느 페이지인지를 모르기 때문입니다. 김 대리는 문서가 열린 모니터 화면을 보면서 열심히 화살표 키를 눌러서 커서(cursor)를 움직입니다. 커서가 가리키는 위치를 따라서 문서를 검색 할 수 있기 때문입니다. , 김 대리는 개념적으로는 문서(, 집합)를 검색하고 있지만, 실제로는 화면에서 커서가 가리키는 특정 문자(, 원소)를 검색하는 일을 계속해서 반복하고 있는 것입니다.

김 대리와 마찬가지로 DBMS(DataBase Management System)에서 집합 형태의 데이터를 검색하기 위해서 사용하는 방법을 스캔(scan)이라 합니다. SQL 문을 수행하여 클래스에서 검색 조건을 만족하는 인스턴스를 인출하는 것을 스캔을 이용하면 다음과 같이 설명하게 됩니다.

해당 클래스에 스캔을 열고, 이동하는 커서가 가리키는 인스턴스가 검색 조건을 만족하면 결과 집합에 담게 됩니다. 커서가 끝까지 가면 스캔을 닫습니다. 그리고 결과 집합을 반환합니다.”

스캔이 열릴 때 굉장히 많은 정보가 설정되는데, 그 중에서 가장 중요한 것은 커서의 이동 방법입니다. 현재 위치에서 다음 위치로 커서를 이동할 때, 인접한 다음 위치 또는 인접한 이전 위치로만 이동할 수 있는 것을 순차 스캔(sequential scan)이라 하고, 임의의 위치로 이동할 수 있으면 임의 스캔(random scan)이라고 합니다. 특별히, DBMS에서는 임의 스캔을 지원하기 위한 방법으로 인덱스(index)라는 것을 사용합니다. 이 때문에 임의 스캔 대신에 인덱스 스캔(index scan)이라고 부르는 것이 일반화 되어 있습니다.

스캔을 이해하기 위해서는 먼저, CUBRID에서 데이터를 물리적인 저장 디바이스에 기록하는 방식을 이해할 필요가 있습니다. 논리적으로, CUBRID는 데이터를 인스턴스로 저장합니다. 동일한 형태의 인스턴스는 동일한 클래스에 저장됩니다.

물리적으로, 클래스는 힙 파일(heap file)이라는 형태로 기록 됩니다. 힙 파일은 여러 개의 페이지로 구성되고, 페이지 안에는 인스턴스에 해당하는 레코드가 저장되어 있습니다. 저장 디바이스와 메모리 사이에서 힙 파일을 읽거나 쓸 때 I/O가 발생합니다. I/O 비용을 최소화 하기 위해서 힙 파일의 한 페이지는 시스템에서 제공하는 I/O 처리 단위와 동일한 크기로 지정 됩니다.(보통 4, 8, 16 Kbyte 등 입니다.)

어떤 클래스가 힙 파일로 저장되어 있으면, 특별히 그것을 기본 클래스(base class)라고 부릅니다(가상 클래스는 기본 클래스가 아닙니다). , 기본 클래스는 인덱스를 가질 수 있고, 인덱스는 인덱스 파일(index file) 형태로 기록 됩니다. 인덱스 파일도 힙 파일과 동일한 크기의 페이지로 구성됩니다(CUBRID는 인덱스 파일 구조를 B+tree 형태로 유지합니다).

따라서, 스캔의 대상은 원칙적으로 기본 클래스가 됩니다. (예외적인 경우는 3.3. 절에서 설명합니다.) 기본 클래스를 스캔 할 때, 기본 클래스에 대응하는 힙 파일의 모든 페이지를 처음부터 끝까지 순차적으로 접근하여 처리하는 방식이 순차 스캔입니다. 그렇지 않고, 인덱스 파일을 검색하여 힙 파일에서 처리해야 하는 페이지들을 먼저 찾아낸 다음에, 찾아진 페이지에 접근하여 처리하는 방식이 인덱스 스캔입니다.

스캔의 종류

순차 스캔

프로젝트 첫째 날에, 김대리는 다음과 같이 employee 클래스를 생성하고 홍길동그리섬을 직원으로 등록했습니다.

csql> CREATE CLASS employee (

csql> Id integer,

csql> Name varchar(20),

csql> Addr varchar

csql> );

csql> INSERT INTO employee VALUES (0, '홍길동', '대한민국 서울');

csql> INSERT INTO employee VALUES (1, '그리섬', '아메리카 라스베가스');

csql> commit;

csql> ;xr

내부적으로 한 개 페이지로 구성된 힙 파일이 생기고, 두 개의 레코드가 생겼을 것입니다. 클래스의 통계 정보로 확인해 보겠습니다. ‘#objects’는 인스턴스의 개수, ‘#pages’는 페이지의 개수를 나타냅니다.

csql> get statistics '#objects' of employee;

csql> get statistics '#pages' of employee;

csql> ;xr

=== <Result of GET STATISTICS Command in Line 1> ===

Result

=============

2

=== <Result of GET STATISTICS Command in Line 2> ===

Result

=============

1

Employee 클래스에는 인덱스가 존재하지 않습니다. 스키마를 확인해 보겠습니다.

csql> ;sch employee

=== <Help: Schema of a Class> ===

<Class Name>

employee

<Attributes>

id INTEGER

name CHARACTER VARYING(20)

addr CHARACTER VARYING(1073741823)

인덱스가 없기 때문에 employee 클래스에 대한 질의문 검색은 순차 스캔으로만 수행됩니다. 현재는 힙 파일 페이지가 1개 이므로 결과가 순식간에 튀어 나옵니다. 스캔 방식을 출력하도록 질의 플랜 단순 보기(257)를 설정했습니다.

csql> ;set level 257;

=== Set Param Input ===

level 257

csql> SELECT * FROM employee WHERE id = 1;

csql> ;xr

Query plan:

Sequential scan(employee employee)

=== <Result of SELECT Command in Line 1> ===

id name addr

=========================================================

1 '그리섬' '아메리카 라스베가스'

1 rows selected.

순차 스캔 방식의 플랜과 그 결과가 인출 되었습니다. 그런데, employee 클래스에 십만 명을 추가로 등록하면 어떨까요? 검색 결과가 여전히 빠를까요? 여러 분도 실제로 한 번 해보세요. 그런데, 십만 번 INSERT 하려면 팔이 좀 아프겠죠. 김 대리는 다음과 같이 한번의 질의문으로 처리했습니다.

csql> INSERT INTO employee

csql> SELECT rownum+100, 'dummy_name', 'dummy_addr'

csql> FROM table({0,1,2,3,4,5,6,7,8,9}) t0(a),

csql> table({0,1,2,3,4,5,6,7,8,9}) t1(a), -- 100

csql> table({0,1,2,3,4,5,6,7,8,9}) t2(a), -- 1,000

csql> table({0,1,2,3,4,5,6,7,8,9}) t3(a), -- 10,000

csql> table({0,1,2,3,4,5,6,7,8,9}) t4(a) -- 100,000

csql> ;xr

100000 rows inserted.

김 대리는 다시 그리섬을 조회해 보았습니다.

csql> ;set level 257;

=== Set Param Input ===

level 257

csql> ;time on

csql> SELECT * FROM employee WHERE id = 1;

Query plan:

Sequential scan(employee employee)

=== <Result of SELECT Command in Line 1> ===

id name addr

=========================================================

1 '그리섬' '아메리카 라스베가스'

1 rows selected.

SQL statement execution time:   1.71 sec

동일한 결과를 얻는데 무려 1.71초나 걸렸네요.

다시 힙 파일 정보를 확인해 보겠습니다.

csql> get statistics '#objects' of employee;

csql> get statistics '#pages' of employee;

csql> ;xr

=== <Result of GET STATISTICS Command in Line 1> ===

Result

=============

100002

=== <Result of GET STATISTICS Command in Line 2> ===

Result

=============

3254

힙 파일이 3,254 페이지로 커졌습니다. 순차 스캔 방식에서는 힙 페이지를 모두 다 검색하기 때문에, 그 수행 비용은 인출되는 결과 집합의 크기와 무관합니다. 단지, 힙 페이지 개수에 의해서 수행 비용이 결정됩니다. 위 질의문에서 인스턴스를 읽어 들이는 CPU 비용을 무시하고 힙 페이지만 고려해 보면, 삼 천 이백 배 이상 검색 시간이 느려질 수 밖에 없겠습니다. 김 대리는 처음처럼 결과가 빨리 튀어 나오도록 추가로 등록한 십 만 명을 삭제했습니다. (시스템 파라미터 auto_commit=off 이면 질의문 수행 후 commit;을 수행해 주어야 서버에 변경 사항이 반영됩니다.)

csql> DELETE FROM employee WHERE id NOT IN (0, 1);

csql> ;xr

Query plan:

Sequential scan(employee employee)

100000 rows deleted.

그리고 다시 그리섬을 조회해 보았습니다. 어떨까요? 순식간에 결과가 튀어 나왔을까요? 여러 분도 실제로 한 번 해보세요.

csql> ;set level 257;

=== Set Param Input ===

level 257

csql> ;time on

csql> SELECT * FROM employee WHERE id = 1;

Query plan:

Sequential scan(employee employee)

=== <Result of SELECT Command in Line 1> ===

id name addr

=========================================================

1 '그리섬' '아메리카 라스베가스'

1 rows selected.

SQL statement execution time:   0.60 sec

수행 시간이 줄어 들었지만, 여전히 0.6초나 걸립니다. 왜 그럴까요? 프로젝트 시작할 때와 동일하게 두 건의 레코드만 있는데 왜 성능이 떨어진 걸까요? 내일 프로젝트 중간 보고를 앞두고 김 대리는 하늘이 노랗게 보이겠지요. 해답은 힙 파일 페이지 구조에 있습니다.

다시 힙 파일 통계 정보를 확인해 보겠습니다.

csql> get statistics '#objects' of employee;

csql> get statistics '#pages' of employee;

csql> ;xr

=== <Result of GET STATISTICS Command in Line 1> ===

Result

=============

2

=== <Result of GET STATISTICS Command in Line 2> ===

Result

=============

3254

이상 합니다. 레코드는 두 개로 줄었는데, 힙 파일 페이지는 여전히 3,254개 입니다.

이러한 현상의 근본적인 원인은 객체지향(Object-Oriented) DBMSCUBRID의 특성에 기인합니다. CUBRID는 인스턴스를 삭제할 때, 그 인스턴스에 삭제되었다는 표시를 해둘 뿐, 실제 내부적으로 삭제하지는 않습니다. 만약 지우게 되면, 이 후에 인스턴스를 삽입하는 경우에 다음과 같은 시나리오 때문에 문제가 생길 수 있기 때문입니다.

예상 시나리오:

김 대리가 진행하는 프로젝트에서는 employee 클래스의 객체를 참조하는 dept 클래스가 있고, dept 클래스에는 누가 어떤 부서에 속하는지에 관한 인스턴스가 저장되어 있습니다. 예를 들어, ‘과학수사1에는 그 팀장으로 그리섬이 지정되어 있다면, dept 클래스의 manager 어트리뷰트는 employee 클래스의 그리섬을 가리키고 있습니다. 다시 말해, ‘그리섬OID(Object IDentifier)dept.manager에 저장하고 있습니다.

그런데, employee 클래스에서 그리섬이 삭제되고 그 영역에 호레이시오가 새로 등록되게 되면, 이와 참조 관계에 있는 dept 클래스의 과학수사1의 팀장이 호레이시오로 바뀌는 사태가 발생합니다.

이러한 이유로, CUBRID에서는 employee 클래스에서 그리섬을 삭제 하더라도 삭제 표시만 하고 그 저장 영역을 재사용하지 못하게 하여, ‘그리섬을 참조하는 다른 클래스의 데이터가 무결성을 유지하도록 합니다. 위 예에서 김대리가 십만건의 인스턴스를 삭제했지만 힙 파일 페이지가 줄지 않은 이유는 바로 객체 참조 무결성을 유지하기 위함이었던 것입니다.

그러나, 객체 참조 기능을 사용하지 않는 경우라면, 삭제된 그리섬의 저장 영역에 새로 입력된 호레이시오를 저장하여 힙 파일 페이지가 커지지 않도록 하는 것이 스캔 성능 측면에서 바람직합니다. 현재 CUBRID RDBMS에 익숙한 사용자들을 위하여 FLOATING OID 기능을 개발 중입니다. FLOATING OID 속성으로 정의되는 클래스에서 인스턴스가 삭제되면, 삭제된 영역을 자동으로 재사용하여 힙 파일 페이지가 커지지 않게 됩니다.

김 대리가 프로젝트 초기에 수행한 순차 스캔에서는 1개 힙 페이지에서 두 개의 레코드를 검색하였으므로 순식간에 수행되었습니다. 두 번째로, 십만 명을 추가로 등록하고 수행한 순차 스캔에서는 3,254개 힙 페이지에서 십만 두 개의 레코드를 검색하여서 1.7초가 걸렸습니다. 마지막으로 십만 명을 삭제하고 나서는 전체 페이지는 동일하지만 빈 페이지(, 삭제 표시된 레코드만 존재하는 페이지)3,253개 이므로 빠르게 지나가고 1개 페이지에서 두 개의 레코드를 검색하였기 때문에 0.6초가 걸린 것입니다. 프로젝트가 진행되면서 기존에 빠르게 수행하던 질의문이 점점 느려 진다는 게 이 때문입니다. 데이터가 삽입되면서 힙 파일이 점점 커집니다. , 데이터가 삭제되어도 힙 파일의 크기는 줄어들지 않습니다. 힙 파일이 커지는 것에 비례하여 순차 스캔은 점점 느려 집니다.

힙 페이지에서 삭제 표시된 부분을 실제로 제거하기 위해서는 데이터베이스를 캠팩션(compaction)해야 합니다. 컴팩션을 통해서 힙 파일 페이지는 삭제 표시된 영역을 재사용하도록 조각 모음이 됩니다. 이 때, 컴팩션에 의해 저장 영역이 바뀌는 인스턴스를 참조하는 어트리뷰트가 있더라도, 참조 OID도 함께 변경되어 데이터 무결성은 유지되게 됩니다.

CUBRID에서는 compactdb 명령어로 컴팩션을 수행합니다. 현재 버전에서는 오프라인(off-line)으로만 지원되므로 서버를 내려야 합니다.

김 대리는 퇴근 후 바로 잠자리에 들었습니다. 그리고 새벽 2시에 다시 출근해서 다음의 명령을 수행했습니다.

sun ksseo ~/ITrack/doc > cubrid server stop sdb; cubrid compactdb –v sdb; cubrid server start sdb

@ cubrid server stop: sdb

 

Server sdb notified of shutdown.

This may take several minutes. Please wait.

++ cubrid server stop: success

CUBRID 2008 R1.4

Pass 1

Class db_root

Pass 2

Class db_root

Class db_user

Class ldb_proxies

@ cubrid server start: demodb

 

CUBRID 2008 R1.4

 

++ cubrid server start: success

sun ksseo ~/ITrack/doc >

김 대리는 다시 그리섬을 조회해 보았습니다. 힙 파일 정보를 볼 수 있도록 질의 플랜 상세 보기(513)를 설정 했습니다.

csql> ;set level 513

=== Set Param Input ===

level 513

csql> SELECT * FROM employee WHERE id = 1;

csql> ;xr

Join graph segments (f indicates final):

seg[0]: [0]

seg[1]: id[0] (f)

seg[2]: name[0] (f)

seg[3]: addr[0] (f)

Join graph nodes:

node[0]: employee employee(2/1) (sargs 0)

Join graph terms:

term[0]: employee.id=1 (sel 0) (sarg term) (not-join eligible) (loc 0)

Query plan:

sscan

class: employee node[0]

sargs: term[0]

cost: fixed 0(0.0/0.0) var 1(0.0/1.0) card 1

Query stmt:

select employee.id, employee.name, employee.addr from employee employee where employee.id= ?:0

=== <Result of SELECT Command in Line 1> ===

id name addr

=========================================================

1 '그리섬' '아메리카 라스베가스'

1 rows selected.

1 command(s) successfully processed.

‘node[0]: employee employee(2/1) (sargs 0)’ 라고 employee 클래스의 인스턴스 2, 힙 페이지 1개 라고 알려줍니다. 결과도 빠르게 나오네요. 편안한 마음으로 퇴근할 수 있게 된 김 대리를 축하해 줍시다.

그 날 이불 속에서 김 대리는 어떤 생각을 하면서 잠에 들었을까요? 다음은 김 대리가 나중에 알려준 내용입니다.

·      단순 테스트가 아닌 운영 시스템에서는 순차 스캔이 발생하지 않도록 해야 한다. 어떻게? 인덱스를 만들어야 된다.

·      운영 시스템에서 특수한 목적으로 순차 스캔이 발생하는 경우에 힙 파일 크기를 확인해 보자. 현재 존재하는 인스턴스 외에 삭제 표시된 저장 영역이 있는 지를 의심하자. 이런 경우에 힙 페이지는 compactdb로 줄일 수 있다.

·      순차 스캔은 그 대상이 되는 클래스 전체에 잠금(lock)을 걸기 때문에, 시스템 동시성을 저하시키는 원인이 된다. 만약, 누군가 순차 스캔을 발생시키면 그 동안 해당 클래스에는 삽입/삭제/변경이 블로킹 된다.

인덱스 스캔

서점에 가서 책을 한 권 집어 보면 가장 뒤 쪽에 인덱스 페이지가 있습니다. 이 페이지를 참조하면 특정 내용이 있는 페이지를 바로 찾아갈 수 있습니다. DBMS에서 인덱스의 역할 또한 바로 이것 입니다.

인덱스는 사용자 데이터에 대한 검색 속도를 높이기 위한 목적으로 부가적인 (, 사용자 데이터와는 무관한) 정보를 저장하는 것입니다. 특별히, PRIMARY KEY, UNIQUE, NOT NULL, FOREIGN KEY 처럼 데이터 무결성을 위하여 DBMS 내부적으로 사용하는 인덱스는 제약 조건(constraint)이라 하여 여기에서 말하는 말하는 인덱스와는 구분합니다.(CUBRID에서 제약 조건은 인덱스를 사용하여 구현되어 있습니다. 따라서, 제약 조건은 데이터무결성을 보장하는 동시에 인덱스 스캔 또한 가능하게 합니다.)

김 대리는 다음과 같이 employee.id 어트리뷰트에 인덱스를 생성했습니다.

csql> CREATE INDEX ON employee (id);

csql> ;xr

1 command(s) successfully processed.

csql> ;sc employee

=== <Help: Schema of a Class> ===

<Class Name>

employee

<Attributes>

id INTEGER

name CHARACTER VARYING(20)

addr CHARACTER VARYING(1073741823)

<Constraints>

INDEX i_employee_id ON employee (id)

인덱스 이름을 명시하지 않았기 때문에, i_employee_id라는 자동으로 부여되는 이름으로 인덱스가 생성 되었습니다. (내부적으로 생성되는 인덱스 파일에는 참조하는 id의 값과 그 값에 해당하는 인스턴스의 OID의 쌍(pair) (키 값,OID)로 구성되는 레코드가 키 값의 오름차순으로 저장됩니다. reverse index이면 키 값의 내림차순으로 생성됩니다.) 이제부터 김 대리가 수행하는 id에 대한 조건 검색 질의문은 다음과 같이 인덱스 스캔 방식으로 동작하게 됩니다.

sun ksseo ~/ITrack/doc > csql sdb -c "SELECT * FROM employee WHERE id = 1"

Query plan:

 

Index scan(e

=

=========================================

1 '그리섬' '아메리카 라스베가스'

su

Q

Index scan(e

=

=========================================

0 '홍길동' '대한민국 서울'

1 '그리섬' '아메리카 라스베가스'

인덱스 스캔은 인덱스 참조와 힙 파일 접근의 두 분으로 구성됩니다. 먼저, 인덱스 참조에서는 해당 인덱스 파일에서 검색 조건을 만족하는 키 값(Key Value)을 찾아내어 그에 대응하는 인스턴스 OID를 읽어 냅니다. employee 클래스에서는 직원이 계속 증가하여 힙 파일이 아무리 커지더라도, ‘id = 1’ 인 직원은 항상 한 명만 존재하므로 OID는 최대 1개 입니다. 그 이후에, 힙 파일 접근에서는 찾아낸 OID에 있는 레코드 위치 정보를 해석하여 원하는 힙 페이지에 즉각적으로 접근하여 해당 레코드를 검색하게 됩니다.

인덱스 스캔 방식의 수행 비용을 생각해 보겠습니다. 힙 파일이 아무리 커지더라도 동일한 검색 조건에서 참조하는 OID 개수는 일정하므로 후자인 힙 파일 접근 비용은 불변입니다. 전자의 인덱스 참조 비용은 인덱스 파일이 커질수록 커지게 될 터이나, 이것은 기본적으로 이진 트리의 깊이 탐색이므로 그 비용은 거의 일정합니다. 따라서, 검색 조건이 동일하다면 인덱스 스캔은 힙 파일 크기에 관계없이 항상 일정한 비용만을 지불하기 때문에 거의 일관된 응답 속도를 보이게 됩니다.

다음은 김 대리가 나중에 추가적으로 알려준 내용입니다.

실제 운영 시스템에서는 모든 질의가 인덱스 스캔 방식으로 수행한다고 보면 된다. 그렇지 않으면, 예외적인 경우이다.

인덱스 스캔 방식에서는 검색 결과가 키 값의 오름차순(또는 내림차순)으로 정렬되는 부가적인 효과가 있다.

기본 클래스의 힙 파일에 삽입/삭제/변경이 일어날 때 마다, 그 클래스에 존재하는 모든 인덱스 파일에서도 삽입/삭제/변경이 일어난다. 따라서, 인덱스가 필요 이상으로 너무 많으면 삽입/삭제/변경 질의의 비용이 커지므로 성능이 저하될 수 있다. 게다가, 발생하는 로그의 양도 커진다. 운영 시스템에서 인덱스 개수는 필요한 요구를 만족하되 최소한으로 유지하는 것이 좋다.

인덱스 스캔은 그 대상이 되는 각각의 인스턴스에 잠금을 걸기 때문에, 검색하는 인스턴스의 개수가 많아지면 과도한 잠금 발생의 원인이 된다. 대신에, 동일한 클래스에서도 서로 다른 인스턴스의 삽입/삭제/변경은 블록 되지 않고 수행되므로 시스템의 동시성이 향상된다.

기타

질의문 중에는 그 수행 과정에서 정렬(sorting)이 필요한 것들이 있습니다. 다음은 정렬을 수행하는 질의문입니다.

ORDER BY : 검색 결과를 정렬하여 인출합니다.

GROUP BY : 검색 결과를 정렬한 다음에 그룹핑하여 인출합니다.

DISTINCT : 검색 결과를 정렬한 다음에 중복을 제거하여 인출합니다.

UNION, INTERSECTION, DIFFERENCE : 두 개의 검색 결과를 정렬하여 한 개의 검색 결과로 합쳐서 인출합니다.

조인을 포함하는 질의문 : 정렬 합병 조인(Sort-Merge Join)이 발생하는 경우, 두 검색 결과를 정렬하여 조인합니다.

인라인 뷰(Inline-View)를 포함하는 질의문: 인라인 뷰의 결과를 스캠 합니다.

질의문의 검색 결과는 최소한 한 번 이상 생성 됩니다. 특히, 위 질의문 들은 검색 결과를 이용하여 최종 검색 결과를 한 번 만드는 연산을 수행합니다. CUBRID는 검색 결과를 저장하는 목적으로 리스트 파일(list file)이라는 형식을 사용합니다.

리스트 파일은 힙 파일과 마찬가지로 페이지 구조이며, 해당 질의문 내에서 아주 짧은 시간 동안만 존재하는 파일입니다.(질의 결과를 저장하는 임시 테이블인데, 질의문이 끝나면 없어지는 것이라고 생각하면 되겠습니다.) 기존의 검색 결과를 읽기 위해서는 해당 리스트 파일을 스캔 해야 합니다.

리스트 파일은 순간적으로 생성되는 파일이므로 당연히 인덱스가 없습니다. 따라서, 리스트 파일에서는 순차 스캔 만이 지원됩니다.

다음 질의문은 employee 클래스에서 현재 유효한 직원을 모두 인출하는 인라인뷰 e를 생성한 다음에 그 결과에서 아메리카에 거주하는 직원들만 다시 인출하고 있습니다. Employee 클래스를 인덱스 스캔 하는 것과 무관하게, 인라인뷰 e는 순차 스캔 하는 것을 확인할 수 있습니다.

csql> ;set level 257

=== Set Param Input ===

level 257

csql> SELECT *

csql> FROM (SELECT * FROM employee WHERE id > 0) e

csql> WHERE addr LIKE '아메리카%'

csql> ;xr

Query plan:

Index scan(employee employee, i_employee_id, employee.id range (0 gt_inf max))

Query plan:

Sequential scan(e)

=== <Result of SELECT Command in Line 1> ===

id name addr

=========================================================

1 '그리섬' '아메리카 라스베가스'

1 rows selected.

1 command(s) successfully processed.

위와 같이 리스트 파일 스캔을 발생시키는 질의문은 운영 시스템 성능 저하의 잠재적인 원인이 됩니다. 데이터가 점점 증가하면서 인라인 뷰의 결과 집합이 커지면 성능 저하가 나타나기 시작합니다. 김 대리는 여러분에게 이렇게 얘기합니다.

·      질의문 작성시에 스캔의 대상은 기본 클래스가 되도록 하라. 질의문을 쉽게 만들려고 아무 생각 없이 정렬이나, 인라인뷰를 사용하지 마라. 위 질의문은 SELECT * FROM employee WHERE id > 0 AND name LIKE 아메리카%; 처럼 기본 클래스를 직접 사용 하라.

·      질의문에서 리스트 파일 스캔이 발생한다면, 꼭 필요한 것인지, 제거할 수는 없는 것인지 한번 더 꼼꼼하게 확인 하라.

 


List of Articles
번호 분류 제목 글쓴이 날짜 조회 수
66 Windows CUBRID2008 R2.0 Tutorial (Windows) cubebridge 2009.08.17 27337
65 기타 CUBRID 2008 R2.0 추가 및 변경 기능 소개 janus 2009.08.15 20663
64 기타 CUBRID 2008 1.x 에서 CUBRID 2.0 64bit로 Migration 3 janus 2009.08.15 15860
63 기타 CUBRID 32bit VS 64bit janus 2009.08.15 17483
62 Java CUBRID JDBC에서 유니코드 사용하기 1 손승일 2009.08.15 27434
61 Java CUBRID Collection Data Type 사용하기 - JDBC 손승일 2009.08.15 24903
» 기타 CUBRID 스캔 이해하기 손승일 2009.08.15 15113
59 Java CUBRID GLO 사용하기 - JDBC 손승일 2009.08.15 23493
58 Install CUBRID 2008 + Textyle 설치 가이드 3 1 Prototype 2009.07.29 18283
57 기타 CUBRID2008 쿼리 작성예제 cubebridge 2009.07.28 24902
56 기타 CUBRID주요 사용 함수 및 연산자 비교 cubebridge 2009.07.28 23450
55 기타 CUBRID2008데이터타입, 함수와 힌트사용법 및 예약어 cubebridge 2009.07.28 18840
54 기타 CUBRID2008 실행계획 분석하기 file cubebridge 2009.07.28 15338
53 Windows eclipse에서 python 및 CUBRID broker_log_top 사용하기 cubebridge 2009.07.28 27271
52 Java JavaSP SampleCode(Pivot기능) cubebridge 2009.07.28 27553
51 Install CUBRID 설치 및 매니저 구동하기(CUBRID 2008 R1.x) CUBRID_DEV 2009.07.18 31530
50 기타 에러 메시지(error) 설명 및 조치 가이드 file CUBRID_DEV 2009.07.11 24420
49 PHP MySQL,PHP 기반에서 CUBRID,PHP 기반으로 포팅하기 시난 2009.07.02 32190
48 Java log4jdbc를 사용한 JDBC 로그 분석 시난 2009.07.02 36391
47 ODBC/OLEDB ODBC드라이버를 이용한 2개 이상의 Statement 사용방법. file seongjoon 2009.07.02 23643
Board Pagination Prev 1 2 3 4 5 6 7 8 9 Next
/ 9

Contact Cubrid

대표전화 070-4077-2110 / 기술문의 070-4077-2113 / 영업문의 070-4077-2112 / Email. contact_at_cubrid.com
Contact Sales