C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
분야별 포럼
C++빌더
델파이
파이어몽키
C/C++
프리파스칼
파이어버드
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

자유게시판
세상 살아가는 이야기들을 나누는 사랑방입니다.
[14793] 스토어드 프로시저의 미신과 파라미터 쿼리
박지훈.임프 [cbuilder] 8417 읽음    2008-07-10 04:54
업무 개발자들이 작업해놓은 결과물을 보다보면, 좀 어이없는 맹신에 빠져서 성능이나 효율을 크게 떨어뜨리는 경우를 볼 때가 있습니다. 그중에 하나가, 스토어드 프로시저에 대한 것입니다.

가장 흔한 경우가, 각 화면 하나 단위, 혹은 디비에 액세스하는 대부분의 쿼리 단위로 스토어드 프로시저를 만들어 쌓아대는 것입니다. 이렇게 할 경우 화면 갯수와 비슷한 갯수 만큼, 혹은 그보다 많은 스토어드 프로시저가 디비에 쌓이게 되죠.

이렇게 작업을 하는 이유는 하나의 미신 때문입니다. SQL은 기본적으로 스토어드 프로시저로 만들어야 최고의 성능을 낼 수 있고.. 디비로 가는 네트워크 부하도 줄일 수 있고.. 뭐 이런 식입니다.

물론 말은 맞습니다. 원론적으로 봤을 때, 일반적인 SQ문들은 처음 실행시에 스토어드 프로시저는 작성 즉시, 그리고 디비의 기동 즉시 그 프로시저의 실행 계획이 생성됩니다. 또, 수없이 길어질 수 있는 SQL 문 대신에 프로시저 이름과 파라미터 정도로만 호출하니까 네트워크 부하도 적어질 수 있지요.

그런데, 그 반대편으로는, 디비 서버에 수없이 쌓이는 프로시저들을 어떻게 관리할 것이냐의 문제도 생깁니다. 특히 테이블의 경우 갯수가 많아지더라도 사용되는 것과 사용되지 않는 것의 구별이 비교적 직관적으로 이루어질 수 있지만, 프로시저는 도대체 사용되는지의 여부와 사용된다면 어디에서 사용되는지를 한눈에 알아보기가 쉽지 않습니다. 물론 부지런해서 프로시저 앞부분에 주석을 잘 작성해두면 이런 문제는 줄일 수 있습니다만, 역시 이것도 관리의 부담입니다.

물론 스토어드 프로시저를 디비 서버에 존재하는 일종의 미들티어다, 비즈니스 로직이다, 라고 간주해버리면 머릿속의 스트레스 리스트에서 빼버릴 수도 있겠지만... 실제로는 스토어드 프로시저가 비즈니스 로직을 완전히 대체하기에는 기능적으로 너무 미약하고, 미들티어로 보기에는 더욱 그렇죠.


그럼 과연 스토어드 프로시저가 이런 부담을 감수하고라도 써야 할 궁극의 해결책인가..하면, 그렇지 않습니다. 먼저, 성능 문제에 있어서, 스토어드 프로시저가 작성 직후, 그리고 기동 직후에 컴파일되어 실행 계획이 만들어지니까 빠르기는 합니다만, 서버 기반의 업무 시스템에서 최초의 한번의 성능이라는 것은 전체에 미치는 영향이 극히 미미합니다. 일반 SQL문들도 한번만 실행되면 실행계획이 만들어지고 캐시되기 때문에, 두번째 실행부터는 스토어드 프로시저의 성능과 차이가 나지 않습니다. (물론 이 부분에 있어서는 데이터베이스 내부의 아키텍처에 관련된 좀 디테일한 변수가 있습니다.)

또, 업무 개발에서는 대단히 긴 SQL문들이 종종 등장하기는 하지만, 그런 SQL은 일부에 불과하죠. select를 이용하는 조회 쿼리라면, 개발자에게는 웬만큼 길다고 해도, 대다수는 몇 kB 이내입니다. 그럼 네트워크의 전송 패킷을 고려할 때, 4kB 이내라면 전송 바이트수가 네트워크에서 부하의 차이가 없는 동일한 한 패킷이라는 얘기죠. 4kB이면 웬만한 select문들은 다 들어가고도 남는 넉넉한 공간이고요.

프로시저의 사용에서 최악의 경우는.. 스토어드 프로시저 안에서 마음놓고 동적 쿼리(혹은 ad-hoc 쿼리)를 만들어내는 것입니다. 보통 DBA나 업무 개발자들이 깔끔한 쿼리를 만들어내기 어려울 때 이런 동적 쿼리를 쓰는데... 동적 쿼리는 말 그대로 SQL문을 문자열 연산으로 만들어내는 것이므로 매번 실행계획이 달라지고, 그래서 성능상 좋지 않다는 것은 알만한 분들은 다 압니다.

그런데, 이런 동적쿼리의 성능 저하 문제를, 스토어드 프로시저로 만들면 해결할 수 있다고 믿는 DBA, 개발자들이 적지 않다는 것입니다. 결론을 말씀드리면, 스토어드 프로시저 내에서 문자열 연산을 해서 동적 쿼리를 하면, 오히려 동일한 동적 쿼리의 SQL문을 직접 날리는 것보다 오히려 더 못한 결과가 나옵니다. 왜냐하면, 작성 시점에서 실행계획이 만들어지는 스토어드 프로시저의 특성상 한번 만들어진 실행계획은 그대로 쭈욱 가는데, 실제로 동작하는 SQL의 내용은 매번 바뀌므로 실행계획의 효율성이 들쭉날쭉할 수밖에 없기 때문입니다. (이런 문제 때문에 매번 실행시마다 스토어드 프로시저를 재컴파일하도록 강제하는 옵션까지 있습니다. 그럼 이런 경우에 프로시저는 도대체 뭥미?)

이에 반해, 어차피 동적 쿼리라면, 차라리 SQL문을 그대로 날리면 매번의 패턴에 따라 실행계획이 캐시되어 더 성능이 좋은 쿼리 결과가 나올 가능성이 높습니다. (물론 동적 쿼리는 최대한 안쓰는 것이 정답이고, 거의 대부분의 경우 동적 쿼리를 통하지 않을 다른 쿼리 튜닝 방법이 있게 마련입니다만)


성능을 위해 정말로 중요한 것은, 스토어드 프로시저가 아니라 파라미터 쿼리(Parameterized Query)입니다. SQL문에서 SQL 문에 조건 등의 값을 직접 써넣지 말고 파라미터로 값을 전달하라는 겁니다. 며칠전에도 델파이 Q/A에서 관련 답변을 한 적이 있는데요.
http://delphi.borlandforum.com/impboard/impboard.dll?action=read&db=del_qna&no=12106

위 링크의 글에서 썼다시피, 일반적으로 델파이나 C++빌더 등의 쿼리 컴포넌트에서 쓰는 파라미터들은 VCL 수준의 기능이 아니라 디비 서버의 기능입니다. 그리고 여기에서 디비 서버에서 파라미터를 쓰는 가장 큰 이유가, 파라미터 값들을 제외한 SQL문으로 공통 실행계획을 캐시하기 때문입니다. 일단 컴파일된 실행계획은 디비 서버 내에서 해시로 관리되는데, 다음번에 SQL 문이 들어오면 컴파일을 하기 전에 해당 해시의 실행계획을 찾아봐서 바로 실행하게 됩니다.

물론 요즘의 대부분의 메이저 디비 서버들은, 파라미터를 쓰지 않은 쿼리(속칭 날쿼리)를 쓰더라도 자동으로 파라미터 쿼리로 바꿔주는, 즉 알아서 파라미터를 추출해서 파라미터 쿼리로 만들어서 실행하는 기능이 있습니다. 하지만 이 기능은 SQL이 조금만 복잡해지면 제대로 동작하지 않기 때문에, 차라리 기대를 하지 않는 편이 낫습니다. 게다가, 이렇게 자동 파라미터가 되지 않는 날쿼리의 경우 매번 자동 파라미터화를 시도하고, 그때마다 실패하기 때문에 오히려 쿼리 속도가 더 느려지게 됩니다. 성능을 높이기 위한 자동화 기능이 오히려 성능을 낮추는 결과가 되는 겁니다.

파라미터 쿼리가 중요한 또 한가지 이유는, 날쿼리의 남발로 인해 정상적으로 실행계획이 생성되어 빠르게 실행되어야 할 더 중요한 SQL들의 실행 속도까지 떨어뜨릴 수 있다는 것입니다. SQL 실행계획은 정적인 것이 아니라 캐시이기 때문에, 실행계획 캐시에 실행계획들이 가득차면 당근 가장 오래된 것부터 차례로 삭제됩니다. 그런데 날쿼리를 남발하면, 조건 값만 다르고 사실은 같은 쿼리들, 즉 수없이 많은 A, A', A'', A''', A'''' 쿼리들이 실행계획 캐시를 가득 채워서 더 중요한 다른 쿼리의 실행계획이 계속 삭제되는 경우가 생기는 거죠.


요약하자면...
스토어드 프로시저의 남발은 관리 부담을 키운다
경우에 따라 스토어드 프로시저가 성능상 더 불리할 수도 있다
무조건 프로시저로 만들고 볼 것이 아니라 생각을 해야 한다 (머리는 둬서 머하나)
성능 측면에서 볼 때 프로시저보다는 파라미터 쿼리가 훨씬 중요하다
Trackback : http://www.borlandforum.com/impboard/impboard.dll/trackback?sn=105462
Tracked from leafriend's me2day   2011-08-23 23:17
스토어드 프로시저의 미신과 파라미터 쿼리 - 난 DB쪽이 너무 약해서 문제. =ㅅ=;...
박지훈.임프 [cbuilder]   2008-07-10 05:17 X
사족입니다만...

업무 개발 프로젝트의 PL, 아키텍트 정도의 리더급이라면, 이런 정도의 데이터베이스 아키텍처에 대한 기본 지식은 알고 있어야 합니다. 업무 시스템에서 가장 느린 부분은 개발하는 산출물 바이너리가 아니라 데이터베이스이고, 데이터베이스에서 성능의 90% 이상이 좌우되기 때문입니다. 데이터베이스의 동작을 모르고 SQL 정도만 아는 정도의 얄팍한 지식으로 업무 개발을 한다면, 제대로 된 업무 시스템이 아니라 그냥 '돌아가기는 하는' 시스템밖에 안됩니다.

그런데 데이터베이스의 성능을 얘기하면 DBA나 개발자나 모두 하나같이 모델링이나 쿼리 튜닝 얘기만 하고 있습니다. 물론 모델링과 쿼리 튜닝이 중요하기는 하지만, 그것이 전부는 아니고, 모델링과 쿼리 튜닝이 아주 잘되어있어도 이런 문제 때문에 극도로 낮은 성능을 내는 시스템도 종종 있습니다. 데이터베이스는 테이블의 집합이나 쿼리 파서 정도가 아니라 그보다 훨씬 복잡한 아키텍처이기 때문에, 모델링과 쿼리 튜닝이 필수조건이기는 해도 충분조건이 되지 못합니다.

담번에 또 땡기면(?) 업무 개발에서의 성능 개선에 관련된 글을 더 써보겠습니다.
(제가 업무 개발을 좋아하는 편이 아니라서 또 땡길지는 잘 모르겠습니다만)
Lyn [tohnokanna]   2008-07-10 06:47 X
오 ㅡ.ㅡ 파라메터 날리는게 DB서버의 기능이었군요...

전 소스를 대충 훑어봐서 컴포넌트가 문자열 조합하고있는줄 알았다는 ㅡ.ㅡ;
곽효근 [hggwak]   2008-07-10 09:48 X
저도 단순히 문자열 대입만 해주는것인줄 알았는데 그게 아니였네요..~
DrK [whitekid]   2008-07-10 11:20 X
Zeos의 PostgreSQL 부분도 모든 파라미터를 직접 Encoding해서 SQL만들어 보내줍니다. 파라미터를 쿼리와 같이 보내주는 PQexecParams/ PQprepare, PQexePrepared 같은 류를 사용하지 않고 PQexec만 죽어라 사용하죠.
장성호 [nasilso]   2008-07-10 11:34 X
햐... 하나 배우네요...

임프님! 땡기는 일이 자주 있었으며 좋겠네요
까막.윤창희 [ggamagui]   2008-07-10 11:45 X
성능 이전에.
실행 파일안에 쿼리문이 있을 경우.
해당 쿼리를 수정할 경우 배포된 모든 곳의 실행 파일을 업데이트 해야 하는 문제는 어떻게 생각하십니까?

DB 안에 있는 뷰나 프로시져를 호출해서 사용하는 프로그램의 경우
해당 뷰/프로시져를 수정하면 끝이지만, 실행 파일에 쿼리가 존재하면 이것도
하나의 문제로 떠오르는데요.

물론 뷰나 프로시져의 파라미터가 바뀌면, 실행 파일도 업데이트 해야 하는 문제도 있네요.

이런 부분에 대한 좋은 해결책이 있으신 분들 있으시나요?
저도 좀 고민하고 있는 부분이라...
까막.윤창희 [ggamagui]   2008-07-10 11:47 X
그리고...
미들웨어 강좌는 아직 진행중이신 건가요?

많이 기다리고 있는 형편이라... 죄송..
박지훈.임프 [cbuilder]   2008-07-10 12:06 X
그건 3티어가 아닌 이상, C/S의 어쩔 수 없는 한계라고 할 수 있는 거죠.
물론 C/S 환경에서 SQL 대신 스토어드 프로시저를 날리면 SQL보다는 훨씬 낫지만, 스토어드 프로시저의 이름도 역시 비슷한 문제가 있습니다. 예를 들어, 프로시저 이름은 어떻게든 유지할 수 있겠지만, 파라미터 갯수가 늘어나거나 타입이 바뀌는 경우에는 역시 똑같은 문제가 생기죠.

SQL이나 프로시저 이름을 실행파일에서 직접 가지고 있어야 하는 외에도, 실제 데이터베이스의 계정과 패스워드를 가지고 있어야 한다는 문제도 비슷한 맥락의 C/S의 문제점입니다. 극단적인 예로, 네트워크 패킷 캡쳐를 해버리면 데이터베이스가 완전히 다 까발려지죠.

이런 문제를 해결하려면 C/S에서는 구조적으로 방법이 없습니다. 물론 말씀하신 것처럼 SQL 대신 프로시저 이름을 씀으로써 상당히 완화시킬 수는 있겠습니다만, 실행파일 내에 SQL이 아닌 프로시저 이름이 들어간다고 해서 문제가 완전히 없어지는 것도 아니니까요.

지금 제가 하고 있는 일도, 개발 컨설팅을 나와서 델파이 기반 3티어 아키텍처를 구축하는 일입니다. 뭐 일의 진행에 따라서는 SI가 되어버릴 수도 있을 거 같고..

이런 이유들도 3티어를 쓰는 이유이기도 한데.. 강좌를 하기로 하긴 했었죠 전에? ^^;;
근데 요즘 밥벌이에 바쁘다보니... ㅎㅎㅎ

+ -

관련 글 리스트
14793 스토어드 프로시저의 미신과 파라미터 쿼리 박지훈.임프 8417 2008/07/10
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.