Jump to content
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr ×
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr

[DocWiki 번역] 행 담아오기(Fetching Rows) (FireDAC)


Recommended Posts

Docwiki에 있는 "Fetching Rows (FireDAC)"를 번역한 글: 번역일: 2022년 3월 29일)

위로 가기: [DocWiki 번역] 명령(command)을 가지고 작업하기 (FireDAC)

Table of Contents


1 커서 다루기 (Handling cursors)

DBMS는 SQL 명령(command)이 실행되고 행(row)을 반환할 때, DBMS 서버에 커서(cursor)를 하나 만든다. 애플리케이션은 만들어진 커서를 이용하여 데이터베이스로부터 행(row)을 담아온다. DBMS에 따라 커서 유형은 여러가지가 있다. 커서 유형을 선택하려면 FDFetchOptions.CursorKind 프로퍼티를 사용한다. 기본값은 FireDAC이 스스로 가장 빠른 커서 유형을 자동으로 선택하기 (ckAutomatic)이다. 이 프로퍼티는 무엇보다 MS-SQL 서버에서 의미가 있다.

DBMS 커서는 자신이 오픈(open)된 곳의 트랜젝션 문맥에 민감하다. 자세한 내용은 "[DocWiki 번역] 트랜젝션 관리하기 (FireDAC)"를 참조한다.

 

2 행 세트를 담아오기 (Rowset Fetching)

행 세트를 담아오기 (Rowset Fetching)에서는 네트워크를 한번 왕복할 때 DBMS 서버에서 담아올 레코드의 갯수를 지정할 수 있다. 이 옵션은 각 SELECT 마다 따로 지정할 수 있어서 실행을 최적화할 수 있다. 즉 RowsetSize 옵션을 명시하여 네트워크 왕복을 최소화할 수 있다.
행 세트의 크기는 FDFetchOptions.RowsetSize 프로퍼티를 통해 다룬다. 숫자가 클 수록 FireDAC이 결과 세트를 모두 가져올 때 까지 걸리는 전체 시간이 짧아진다. 하지만, 데이터 담아오기(네트워크 왕복) 단위 별로 걸리는 시간은 더 길다. 그리고 "높은" 값으로 시작하면 성능이 느려지기 시작한다. 실제 상황에서 "높은" 값은 2000-3000 정도이다.

주의: 행 세트를 담아오기 (Rowset Fetching)를 모든 DBMS에서 지원하지는 않는다. 하지만, FireDAC는 Rowset Fetching을 모방(emulate)할 수 있는 능력이 있다. Rowset Fetching을 모방(emulate)한 경우, 일반 가져오기에 비해 실제 속도가 50% 정도 향상된다.

FireDAC은 FetchOptions.Mode 프로퍼티에 지정된 방식으로 행 세트를 담아온다.

  • fmOnDemand-- 데이터셋 안에서 다른 레코드를 가리키기 위해 위치를 이동하려고 할 때, 옮기려는 곳이 마지막에 담아온 레코드를 벗어난 곳이라면 자동으로 해당 행 세트를 담아온다. 
  • fmAll--SQL 명령이 실행되는 즉시 모든 행 세트를 자동으로 담아온다. FetchAll 메소드를 호출하는 것과 비슷하다.
  • fmManual--행 세트를 담아오려면 프로그래머가 직접 FetchNext 또는 FetchAll 메소드를 사용해야 한다.
  • fmExactRecsMax--명령이 실행되는 즉시 모든 행 세트를 자동으로 담아온다. 만약 담아온 행의 갯수가 FetchOptions.RecsMax에 지정된 숫자와 일치하지 않으면, 예외가 일어난다.

FetchOptions.UnidirectionalTrue이면, 다음 행세트를 담아오기 전에, 메모리에서 이전 행 세트를 버린다. 이렇게 하면 대용량 결과 세트를 가져올 때 PC 메모리를 보존할 수 있다.

레코드 전체를 담아온 후에는, TFDDataSet.SourceEOFTrue로 지정되고, 해당 명령(command)은 FetchOptions.AutoClose 프로퍼티에 지정된 대로 닫힘(Closed) 처리 된다. 그렇지만 데이터셋 자체는 닫히지(Closed) 않는다.

주의: 자세한 내용은 명령 묶음 일괄 실행 참고.

갓 담아온 레코드를 액세스하려면, TFDDataSet.AfterGetRecord 이벤트 핸들러를 사용한다.

 

3 행(Row) 페이지 나누기

FetchOptions.RecsSkipFetchOptions.RecsMax를 사용하면 결과 세트를 페이지 나누기 할 수 있다. 커서가 열린 후에, 첫 위치에서 RecsSkip 값 만큼 레코드를 건너뛰고 나서 그 뒤에 있는 레코드를 시작으로 RecsMax 값 만큼 레코드를 담아온다. 명령문이 이미 준비된(prepared) 상태라면 RecsSkipRecsMax를 변경해도 효력이 없기 때문에 이 경우에는 다음 행(row) 페이지를 담아오기 전에, SQL 명령(command)을 준비되어 있지 않은 상태로 돌려 놓은 후에 다시 실행해야 한다. 예를 들어,

FDQuery1.FetchOptions.RecsSkip := 0;
FDQuery1.FetchOptions.RecsMax := 100;
FDQuery1.Open;
// 행(row)을 처리한다.

FDQuery1.Disconnect;
FDQuery1.FetchOptions.RecsSkip := 100;
FDQuery1.Open;
// 행(row)을 처리한다.

FDQuery1.Disconnect;
FDQuery1.FetchOptions.RecsSkip := 200;
FDQuery1.Open;
// 행(row)을 처리한다.

 RecsSkip 그리고/또는 RecsMax 프로퍼티가 명시되는 시점에, FireDAC은, 가능하다면, 맨 윗 행과 가져올 행의 갯수가 적용되도록 하기 위해 기존 SELECT 명령을 변경한다.

 

4 지연된 담아오기 (Delayed Fetching)

결과 세트(result set)에는 BLOB 컬럼 그리고/또는 중첩 데이터셋 컬럼이 포함될 수 있다. 이런 컬럼들이 있으면 대체로 결과 세트를 담아오는데 걸리는 시간이 느려진다. FireDAC에서는 이런 컬럼들에 한하여 데이터를 바로 가져오기를 미뤄두었다가 정말 필요할 때가 되면 가져오도록 할 수 있다. FetchOptions.Items 프로퍼티에 넣는 옵션에 따라 다음과 같이 동작한다.

  • fiBlobs 옵션이 빠져있을 때, FireDAC은 BLOB 값 담아오기를 지연한다. 이 경우, 데이터셋 안의 현재 레코드에 들어있는 BLOB 컬럼의 값을 담아려면 FetchBlobs 메소드를 사용하거나, 또는 Mode <> fmManual인 상태에서 BLOB 값을 처음으로 읽어서 FetchBlobs 메소드가 자동으로 호출되로록 한다.
  • fiDetails 옵션이 빠져있을 때, FireDAC은 충첩된(nested) 디테일 데이터셋 담아오기를 지연한다. FetchDetails 메소드는 데이터셋 현재 레코드에 해당하는 중첩된 디테일 데이터셋 담아오기를 수행한다. fiDetails"[DocWiki 번역] 마스터-디테일 관계 (M/D)" 다루기를 제어한다. 

지연된 담아오기 SQL 명령(command)을 만들려면, Update Command Generation을 참고한다.

주의: FetchOptions.Items에서  fiBlobs 또는 fiDetails를 빼도, SQL 명령의 해당 SELECT 구문의 항목은 달라지지 않는다. DBMS가 BLOB 값을 "by value(값)로" 전달한다면(예: Oracle LONG, MySQL, MS-SQL 서버, SQLite), 해당 BLOB 값이 해당 네트워크를 통해 클라이언트로 전달되지만, 클라이언트 레코드 캐시(cache)에는 저장되지 않는다. 이와 달리, DBMS가 BLOB 값을 "by reference(참조)"로 전달한다면(예: Oracle CLOB / BLOB, Interbase, Firebird), 해당 BLOB 값은 클라이언트로 전달되지도 않고 저장되지도 않는다.

 

5 행을 다시 담아오기 (Refetching Rows)

가끔은, 이미 있는 데이터셋에 새 결과 세트를 덛붙이거나, 또는 애플리케이션에서 행(Row)들을 다시 담아와야 하는 상황이 있다. 이때는 FetchAgain 메소드를 사용한다.

주의: 데이터셋을 새로고침 할 때에는 Refresh 메소드를 사용하라.

 

6 일반 사용 사례 (General Usage Cases)

경우 별 알맞은 FetchOptions 설정은 다음 표와 같다.

경우 설명
대규모 레코드이고, 메모리 사용이 제한될 때, 담아오기 시간을 최소화하려면 CursorKind = ckDefault 또는 ckForwardOnly
Mode = fmOnDemand
RowsetSize = 1000
Unidirectional = True
쿼리를 오픈(Open)할 때 지연이 있어도, 담아오기 시간을 최소화하려면 CursorKind = ckDefault
Mode = fmAll
RowsetSize = 1000
쿼리를 오픈(Open)할 때 지연을 최소화하려면 CursorKind = ckDynamic
Mode = fmOnDemand
RowsetSize = 50
Items에서 fiMeta를 제외
읽기-전용 데이터셋 Items에서 fiMeta를 제외,
또는 UpdateOptions.RequestLive를 False로 지정.
여러 결과 세트(result set)를 가지고 묶음 일괄 실행(batch command)을 할 때 AutoCloseFalse
대규모 레코드이고, BLOB 값들이 들어있고 메모리 사용이 제한될 때, 담아오기 시간을 최소화하려면 Items에서 fiBlobs를 제외,
위 설정과 섞어서 사용

 

7 기타 자료 (See Also)

 

7.1 예제(Samples)

이 댓글 링크
다른 사이트에 공유하기

이 토의에 참여하세요

지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.

Guest
이 토픽(기고/질문)에 답하기

×   서식있는 텍스트로 붙여넣기.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   이전에 작성한 콘텐츠가 복원되었습니다..   편집창 비우기

×   You cannot paste images directly. Upload or insert images from URL.

 공유하기

×
×
  • Create New...

중요한 정보

이용약관 개인정보보호정책 이용규칙 이 사이트가 더 잘 작동하기 위해 방문자의 컴퓨터에 쿠키가 배치됩니다. 쿠키 설정 변경에서 원하는 설정을 할 수 있습니다. 변경하지 않으면 쿠키를 허용하는 것으로 이해합니다.