Framework/Database2009. 3. 24. 00:45

클라이어트 프로그램이 웹이라면 아마 Keyset이나 Dynamic 커서는 99.9%의 확률로 써야 할 경우가 없을 것이다. connectionl less한 웹에서 사실 동시성은 거의 의미가 없다. 사실 별도의 어드민 작업이 없다고 확신할 수 있다면 굳이 commited data만을 읽을 필요조차 없다.

따라서 대부분 사용하는 커서는 Forward Only, Static, Anonymous(가칭) 3가지이다. 프로그래머가 의도하든 의도하지 않았든 말이다.

Forward Only는 쿼리의 결과셋 모두가 클라이언트 프로그램에 필요할경우 사용하며, 셋을 유지하지 않아도 되고 네트워크 패킷도 여러 로우를 묶어서 던지기 때문에 효율적이다.

Stati은 쿼리의 결과셋 모두 혹은 대부분이 클라이언트에 필요할경우 사용하며, 셋을 임시 영역에 유지하는데 메모리 비용과 패킷수량이 많아지는 단점이 있지만 커서의 앞뒤 이동이 가능하다는 점이 장점이다.

Anonymous는 쿼리의 결과셋의 처음 일부만 필요할 경우 사용하며, 패킷 수량이 많아지는 단점이 있지만 부분범위 처리가 가능하다는 장점이 있다.


커서를 선택하는 일반적인 기준은 아래와 같다.
1. result Size : 결과 셋의 전체 사이즈가 크면 Static은 쓰지 않아야 한다.
2. result Size에서 필요한 Data의 비율 : 퀴리 결과에 비해 클라이언트 필요한 부분이 아주 일부분에 불과하다면 Anonymous 커서를 사용해야 한다.
3. 필요한 커서 행동 (스크롤링 여부, 업데이트 가능 여부) : 쿼리결과 대부분이 사용될경우 스크롤링이 필요없다면 ForwardOnly, 스크롤링이 필요하다면 Static을 고려해볼수 있다. 단 단순히 갯수만을 알고자 한다면 굳이 Static을 선택하지 않고 차라리 select count(*) 쿼리를 별도로 던지는게 더 빠를수도 있다.
4. 커서 자체의 속도(예컨데 open 시) : 커서 자체의 속도는 필요한 정보가 가장 적기 때문에Forward Only가 다른 방식보다 빠르다.
5. 다른 유저가 변경했을때의 변경의 visibility level : 앞에서 말했듯이 connection less 환경에서는 거의 의미가 없지만 특이 케이스일경우 고려해 볼 수 있다.


쿼리셋의 전체 혹은 일부만을 원하는지의 여부가 가장 결정적인 선택 기준이 된다. 만약 select의 결과가 단지 한개의 row이거나 small Set이고 전체 셋을 모두 사용할 것이라면 그냥 default 커서(Forward Only)을 사용한다. 그러나 만약 update가 가능해야 한다면  default커서는 사용할 수 없다. 디폴트 커서는 커서의 행의 수를 미리 알 수 없고 absolute 등의 이동도 불가능하다.

여기서는 상세하게 적지 않겠지만 다이나믹 커서는 내부의 임시 영역에 Set 형태를 만들지 않기 때문에 처음 몇개의 row만 사용한다면 스태틱이나 키셋 커서에 비해 빠를 수 있다. 단 조인을 사용하는 경우 다이나믹 커서는 락킹 처리 문제로 더 느려진다. 키셋이나 스태틱 커서만이 absolute fetch가 가능하다. 반면에 이 두 방식의 커서는 Set을 tempDB에서 build 하기 때문에 tempDB 사이즈에 영향을 받는다.
 
위 기준에 맞춰 커서의 종류를 선택하였으면 앞글에서 적었듯이 쿼리를 전체범위처리냐 부분범위처리냐에 맞게 바꿀수 잇는 능력이 필요하다.


.... 이게 커서의 끝이 아니다.

프레임워크를 개발하는 입장에서 본다면 위 방식은 심각한 문제가 있다. 커서를 사용하는 방식은 DB마다 상이하며 또 모든 DB가 이를 지원하지도 않는다. MSSQL의 경우처럼 어떤 커서를 선택하느냐에 따라 JDBC URL을 바꿔야 한다면 모든 프로그래머가 이를 기억하고 있을리가 없다. 게다가 2005ver에서는 또 다르다!. 프레임워크는 어려운걸 쉽게 만들수는 없더라도 복잡한걸 간결하게는 만들어줘야 하는데 설사 그게 성능등의 이유로 어쩔수 없다고 하여도 위의 선택기준은 지나치게 문제가 복잡해진다.

그래서 위의 커서를 이해하였다면 그 내용을 모두 잊어버려야 한다. 농담이 아니다. 위 커서방식들은 당신이 아주 전문가이고 개별적인 환경하에서의 특이한 케이스가 아니라면 쓸수가 없다. 물론 그렇다고 과거의 무지의 상태로 돌아가서 우연히 좋은 방식이 선택이 되기를 혹은 드라이버가 알아서 좋은걸 선택해주지 않을까 하며 기도하는 것도 방법은 아니다.


사실 앞에서 커서의 모든 종류를 얘기한 것이 아니다. 단지 "서버커서"의 모든 종류를 얘기했을 뿐이다. 서버커서는 앞의 PPT에서 보이듯이 커서 - 일종의 포인터 -가 DB 서버에 위치한다.

Client Cursor는 말 그대로 Cursor의 위치가 데이타베이스가 아닌 클라이언트에 위치하는 모델이다. 후에 좀더 자세히 설명하겠지만 초기의 데이타베이스는 서버 커서를 지원하지 않았고 프로그래머는 사용하는 언어로 DBMS 벤더가 제공하는 DB-Library 커서 함수들을 사용하여 각자 구현하여야만 했다.

이후 각 DBMS 업체가 Server Cursor를 제공함으로써 Client Cursor 모델 방식은 한동안 잊혀졌으나 최근의 인터넷 환경과 맞물려 다시 사용되고 있는 모델이다. Client Cursor는 결과셋 전체를 한꺼번에 클라이언트에게 전송하며 이후 서버와 연결과 무관하게 클라이언트는 커서를 동장시킬수 있다. 즉 데이타베이스는 일단 결과셋 모두를 클라이언트게 전송하면 더이상 클라이언트와 연결을 유지할 필요가 없고 이후 커서 동작은 모두 클라이언트에 버퍼링된 결과 셋에서 이루어지게 된다. 이는 인터넷의 Stateless 환경과 매우 잘 맞기 때문에 ADO.NET의 Reader나 DataSet 그리고 JDBC의 RowSet이 클라이언트 커서 모델을 사용한다. 현재는 Server Cursor가 더 많이 사용되고 있지만 앞으로 점점 더 Client 커서를 사용하는 경우가 많으리라 생각된다.

클라이언트 커서를 사용하기 위한 가장 중요한 서버 커서의 문제와 관련이 있다. 앞의 서버 커서는 쿼리의 결과셋의 크기와 실제 클라이언트가 사용하는 비율이 커서 선택의 제 1기준이었지만 클라이언트 커서는 쿼리의 결과셋 모두를 사용해야 의미가 있고(그렇지 않으면 Forward Only 커서의 문제점을 답습하게 된다.) 이는 달리 말해 페이징 처리등의 이유로 결과셋의 일부만 사용된다면 애초에 쿼리를 페이지 기반으로 수정해야 하고 할 수 있어야 한다.



이글과 다음 글들을 처음 생각했던 7년전에 올렸다면 어떻게 됐을까? 하고 가끔 생각한다. 그때에 나는 클라이언트 커서 방식이 앞으로 가장 효율적이기에 가장 널리 사용될것이라고 생각했지만 7년동안 내가 참여한 프로젝트들을 제외하면 사실 위와같은 방식을 사용하는 경우를 보지 못했다. (그렇다고 상황에 맞게 서버 커서를 적절하게 사용하는 경우도 못봤다.)

그렇기에 아마도 이글과 다음의 커서 글들은 사실이 아니다. 무슨 말이냐면 클라이언트 커서에 대한 이야기와 사용의 장점은 상대적이고 주관적이며 그리고 아마도 소수이다. common is not common 상식이 보편이 아닌것처럼 보편 또한 사실이 아니지만 우리는 흔히 보편이 사실이라고 생각한다. 대부분의 책이나 인터넷등에서 아예 커서에 대한 언급 자체가 거의 없다시피 하기 때문에 자체 실험 데이타를 제외하면 충분한 근거를 찾기가 어렵다. 그래서 아마도 이글들은 사실이 아니고 보편적이지 않다.

'Framework > Database' 카테고리의 다른 글

Framework Cursor (cursor in MySql)  (1) 2010.02.24
Framework - client cursor  (0) 2009.03.26
프로시저 vs SQL  (0) 2009.03.23
Framework - 커서(Anonymous)  (0) 2009.03.19
Framework - 커서(Keyset, Dynamic)  (0) 2009.03.13
Posted by bleujin