본문 바로가기

Programming/JSP

oracle 실행계획에 따른 preparedStatement의 문제점.


PreparedStatement가 SQL문의 수행계획을 재사용할 수 있는 장점이 있지만
그것은 역으로 말하면 치명적인 약점이 될 수 있습니다.

예를들어)
select하는 테이블의 특정칼럼에 'A'라는 데이터와 'B'라는 데이터가 존재하고
그 분포도가 A=99%, B=1%만 존재한다면 SQL문의 검색조건이 'B'를 검색할경우
테이블의 Index를 타는것이 바람직하지만 'A'를 검색할경우 전체 테이블을 스켄해야
할것입니다.

하지만 PreparedStatement로 어느 조건을 검색하든지간에 한번 수행된 이후로는
Query 실행 계획을 재사용 함으로서 앞으로 수행되는 Query의 식은 무조건 Index를
타거나 또는 무조건 FullScan을 하는 형태로 실행계획을 수립할 것입니다.

이는 통계데이터를 적절히 활용하지 못하게되는 치명적인 오류가 발생할 수 있음을
이야기 할 수 있습니다.

따라서 제 짧은 소견으로는 실행계획이 특정 값에 의해 크게 바뀌는 것이 아닌경우엔
PreparedStatement의 SQL Execution plan재사용이 효율적이라고 볼 수 있으며 반면에
특정 값에 따라 실행계획을 재생성 해야 할 경우엔 Statment를 사용하는것이 바람직
할 수 있습니다. 왜냐면 실행계획을 재생성하는것은 아주 짧은 시간에 수행 될 수 있
지만 한번 잘못 생성된 실행계획에 의해 수행되는 SQL문은 엄청난 시간적 비용을 낭비
할수 있습니다.

일반적으로 OLTP성 업무엔 PreparedStatement사용하여 Plan재사용을 유도하며 반면
OLAP와 같이 잦은 SQL문 수행은 발생하지 않지만 많은 량의 데이터를 처리해야 할때는
Statement를 사용하는것이 바람직하다고 할 수 있습니다.

들리는 이야기로는 요즘 DBMS는 너무나 그 지능이 좋아서 PreparedStatement를 쓸지라도
너무 많은 Resource를 지속적으로 사용할 경우 실행계획을 재수립 한다고도 하는군요.

결론적으로 Prepared Statement가 만능 해결사는 아니라는 것을 말씀드리고 싶습니다.


////////////////////////// 불펌입니다 ㅠㅠ
출처 : http://jennifer.co.kr/~java/bbs/read.cgi?m=devtip&b=jdbc&c=r_p&n=1023286823&p=25&s=d 


//////////////보충입니다.
 preparedStatement를 사용하면 오라클이 binding 변수를 사용한다고 앞선 포스팅에서 알려드렸습니다.
바인드 변수를 사용한다는 것은 SQL이 최초 수행될 때 최적화를 거친 실행계획을 캐쉬에 저장하고,
실행시점에는 그것을 그대로 가져와 값만 다르게 바인딩하면서 반복 재사용한다는 것 까지 알려드렸는데요,
여기서, 변수를 바인딩하는 시점이 최적화 이후라는 사실을 눈여겨 볼 필요가 있습니다.
즉, 나중에 반복 수행될 때 어떤 값이 입력될지 알 수 없기 때문에 옵티마이저는(SQL 최적화를 담당하는 DBMS엔진)
조건절 칼럼의 데이터 분포가 균일하다는 가정을 세우고 최적화를 수행합니다. 칼럼에 대한 히스토그램 정보가
딕셔너리에 저장되어 있어도 이를 활용하지 못한다는 것이죠. 칼럼 분포가 균일할 때는 이렇게 처리해도 나쁘지 않으나,
그렇지 않을 때는 실행 시점에 바인딩되는 값에 따라 쿼리 성능이 다르게 나타날 수 있습니다. 이럴 때는 바인드 변수를
사용하는 것보다는 상수 값을 사용하는 것이 나을 수 있는데, 그 값에 대한 칼럼 히스토그램 정보를 이용해 좀 더 최적의
실행계획을 재수립할 가능성이 높기 때문입니다.

출처 : http://www.dbguide.net/db.db?cmd=view&boardUid=148212&boardConfigUid=9&categoryUid=216&boardIdx=137&boardStep=1