- 최초 수행시 최적화
- 실행계획 라이브러리 캐시 적재
- 실행시 바인딩
1 | 번호 > : NO | 5 | 번호 between :NO and :NO |
2 | 번호 < : NO | 6 | 번호 > :NO and 번호 <= :NO2 |
3 | 번호 >= : NO | 7 | 번호 >= :NO and 번호 < :NO2 |
4 | 번호 <= : NO | 8 | 번호 > :NO and 번호 < :NO2 |
1~4번은 선택도 5%로 계산하고, 5~8번 같은 =조건이 아닌 부등호나 Between 같은 범위 기반 검색은 0.25%
로 계산한다.
{section}
{column:width=25}
카디널리티 = 선택도 * 전체 레코드 수
{column}
{column:width=25}
{column}
{section}
조건절에 따른 바인드변수 |
---|
{code:sql} SCOTT@orcl > create table t as 2 select rownum no from dual connect by level <= 1000; |
테이블이 생성되었습니다.
SCOTT@orcl > analyze table t compute statistics for table for all columns;
테이블이 분석되었습니다.
SCOTT@orcl > explain plan for
2 select * from t where no <= :NO;
해석되었습니다.
SCOTT@orcl > select * from table
2 (dbms_xplan.display(null,null,'basic rows'));
Id | Operation | Name | Rows |
0 | SELECT STATEMENT | 50 | |
1 | TABLE ACCESS FULL | T | 50 |
SCOTT@orcl > explain plan for
2 select * from t where no between :no1 and :no2;
해석되었습니다.
SCOTT@orcl > select * from table
2 (dbms_xplan.display(null,null,'basic rows'));
Id | Operation | Name | Rows |
0 | SELECT STATEMENT | 3 | |
1 | FILTER | ||
2 | TABLE ACCESS FULL | T | 3 |
9 개의 행이 선택되었습니다.
|
위의 테스트 결과로 바인드 변수는 정해진 기준에 따라 선택도를 구하고 전체 레코드 수를 곱하여 비용을 계산함을 알 수 있다.
|| 바인드 변수가 아닌 상수 조건식 ||
| {code:sql}
SCOTT@orcl > explain plan for select * from t where no <= 100;
해석되었습니다.
SCOTT@orcl > select * from table(dbms_xplan.display(null,null,'basic rows'));
------------------------------------------
| Id | Operation | Name | Rows |
------------------------------------------
| 0 | SELECT STATEMENT | | 99 |
| 1 | TABLE ACCESS FULL| T | 99 |
------------------------------------------
8 개의 행이 선택되었습니다.
SCOTT@orcl > explain plan for select * from t where no between 500 and 600;
해석되었습니다.
SCOTT@orcl > select * from table(dbms_xplan.display(null,null,'basic rows'));
------------------------------------------
| Id | Operation | Name | Rows |
------------------------------------------
| 0 | SELECT STATEMENT | | 99 |
| 1 | TABLE ACCESS FULL| T | 99 |
------------------------------------------
8 개의 행이 선택되었습니다.
|
바인드변수를 사용할 때는 정확한 컬럼 히스토그램에 근거하지 않고 카디널리티를 구하는 정해진 계산식을 기초해 비용을 계산하므로 최적이 아닌 실행계획을 수립 할 가능성이 높다. 또한 바인드 변수를 사용하면 파티션테이블을 쿼리 할때 파티션 레벨 통계 정보를 이용하지 못하게 되므로 가끔 악성 실행계획을 수립하는 경우 발생.
{*}Peeking이란?*
단어가 의미하듯이 SQL이 첫 번째 수행되면서 하드파싱될 때 함께 딸려 온 바인드 변수 값을 살짝 훔쳐보고,
그 값에 대한 컬럼 분포를 이용하여 실행계획을 결정하는 것
-이런저런 이유로 바인드 변수 Peeking 기능을 사용하지 않는다.
SQL> alter system set "_optim_peek_user_binds" = false; <-- 비활성화
SQL> alter system set "_optim_peek_user_binds" = true; <-- 활성화
{*}적응적 커서 공유란?*
Peeking 기능의 문제를 해결하기 위해 11g에서 한번 더 개선된 기능이 나온것
입력된 바인드 변수 값의 분포에 따라 다른 실행계획이 사용되도록 하는 것이다.
.
.
SELECT /*+ FULL(a) */ *
FROM 아파트매물 a
WHERE :CITY IN ('서울시', '경기도')
AND 도시 = :CITY
UNION ALL
SELECT /*+ INDEX(a idx01) */ *
FROM 아파트매물 a
WHERE :CITY NOT IN ('서울시', '경기도')
AND 도시 = :CITY;
IF :CITY IN ('서울시', '경기도') THEN
SELECT /*+ FULL(a) */ *
FROM 아파트매물 a
WHERE 도시 = :CITY;
ELSE
SELECT /*+ INDEX(a idx01) */ *
FROM 아파트매물 a
WHERE 도시 = :CITY;
END IF;
바인드 변수를 사용하게 되면 cursor의 재활용 측면에서 좋기는 하지만 꼭 바인드 변수가 최적화라는 해법은 되지 못한다.