펑션 내부 WHERE절 변수에 따른 실행계획 변경 5

by kdg99 [Oracle Tuning] ORACLE [2024.06.13 10:53:59]


안녕하세요 이번에 근태관련 쿼리를 만들다가 이상한 현상을 발견하여 질문드립니다.

여러 신청서의 일자 및 시간을 조회하여 해당 근무인원의 일자별 근태현황을 보여주는 쿼리인데요

 

함수 바깥에서 직접 실행하는 경우에는 속도가 빠른데 함수로 만들어서 처리하면 속도가 느려지더라구요

그래서 원인을 찾다가 WHERE절에 기간 체크하는 부분에서

SELECT A.*
  FROM TABLE_RQST A
 WHERE A.RQST_DATE BETWEEN V_FROM_DATE AND V_TO_DATE
--AND A.RQST_DATE BETWEEN '19000101' AND '99991231'

 

주석처리된 부분처럼 명시적인 값을 넣어주니까 속도가 매우 개선되더라구요

해당쿼리가 몇 개 있는데 한 군데라도 저렇게 명시적인 값 비교를 추가해주면 전체속도가 개선됩니다.

 

그런데 마냥 저렇게 처리해두기에는 원인도 못 찾겠고 불안해서

혹시 관련 키워드나 원인을 아시는 분이 있다면 의견을 구하고 싶습니다.

 

by 마농 [2024.06.13 11:16:18]
-- 직접 수행할 때도 바인드 변수로 수행해서 직접 줄때와 실행계획 비교해 보세요.
SELECT a.*
  FROM table_rqst a
 WHERE a.rqst_date BETWEEN :v_from_date AND :v_to_date
;

 


by kdg99 [2024.06.13 13:41:20]

계속 검색해본 결과 정확히 일치하는 상황이 있어 링크 남깁니다, 답변은 크게 도움이 되지 않는 것 같지만요

https://forums.oracle.com/ords/apexds/post/pl-sql-speed-issues-when-using-a-variable-1494


by kdg99 [2024.06.13 14:16:32]

https://stackoverflow.com/questions/72068511/query-execution-is-slow-in-pl-sql-anonymous-block

위의 케이스도 동일한 케이스라 생각하여 XPLAN 출력해본 결과 SQL_ID는 다르고 큰 차이는 없었습니다

read값은 여러 번 실행해보니 안 보이더라구요

FN_BINDING이 명시적 비교절을 추가하지 않은 함수

FN_LITERAL이 명시적 비교절을 추가한 함수입니다

------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |            |      1 |        |      1 |00:00:14.17 |     115K|
|   1 |  SORT AGGREGATE                    |            |      1 |      1 |      1 |00:00:14.17 |     115K|
|   2 |   COLLECTION ITERATOR PICKLER FETCH| FN_BINDING |      1 |    106K|  53196 |00:00:14.17 |     115K|
------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------
| Id  | Operation                          | Name       | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                   |            |      1 |        |      1 |00:00:14.24 |     115K|    217 |
|   1 |  SORT AGGREGATE                    |            |      1 |      1 |      1 |00:00:14.24 |     115K|    217 |
|   2 |   COLLECTION ITERATOR PICKLER FETCH| FN_LITERAL |      1 |    106K|  53196 |00:00:14.24 |     115K|    217 |
---------------------------------------------------------------------------------------------------------------------

 


by kdg99 [2024.06.13 13:12:01]

바인드 변수로 직접 수행한 결과는 직접 줄 때와 똑같았습니다.

아마 함수 안에 있을 때 생기는 문제 같습니다

함수에서 파이프라인을 반환하고 있기는 합니다만 이건 관련 없을 것 같은데 영문을 모르겠네요,,

리터럴 변수비교를 추가하고 안하고의 경우 데이터의 양만큼 시간 차이가 나는 것 같은데


by kdg99 [2024.06.13 15:11:39]

키워드를 찾아서 계속 찾아본 결과 프로시저나 함수안에 들어가는 경우

WHERE 절에 변수가 사용되는 경우에 발생하는 옵티마이저 문제 같네요

되게 옛날부터 있었던 문제이고, 딱히 왜 발생하는지 해결방법은 뭔지 찾지는 못 했습니다.

몇몇 의견에는 parameter sniffing 문제가 계속 언급되긴 하네요

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입