As I have a friend who really loves SYS_CONTEXT; I showed him the blog.
In the following discussion he stated (more/less
)
I should not have this problem at all, as I'm not using SYS_CONTEXT directly, but wrapped in a package like select * from xyz where a = pkg.get_ctxt('BLAH');
As a proud member of BAAG, I want clarify this should.
The preparation of my environment is nothing specific and quite close to Connors:
create table t ( x varchar2(10), y char(100)); insert into t select 'a', rownum from dual / insert into t select 'b', rownum from dual connect by level <= 100000 / commit; create index ix on t ( x ) ; exec dbms_stats.gather_table_stats('','T',method_Opt=>'for all columns size 5'); drop context blah; create context blah using my_package; create or replace PACKAGE MY_PACKAGE AS procedure my_proc(p_val varchar2); function get_sys_context return varchar2; function get_variable return varchar2; END MY_PACKAGE; create or replace package body MY_PACKAGE AS my_var varchar2(10); procedure my_proc(p_val varchar2) is begin my_var := p_val; sys.dbms_session.set_context('BLAH','ATTRIB',p_val); end my_proc; function get_sys_context return varchar2 is begin return sys_context('BLAH','ATTRIB'); end get_sys_context; function get_variable return varchar2 is begin return my_var; end get_variable; end MY_PACKAGE;
Now the real testcase starts:
exec my_package.my_proc('a'); select my_package.get_sys_context from dual; select my_package.get_variable from dual;Just shows everything works as expected:
PL/SQL procedure successfully completed.
GET_SYS_CONTEXT
---------------
a
GET_VARIABLE
---------------
a
So let's check the optimizers opinnion:
select /*+ gather_plan_statistics */ count(y) from t where x = my_package.get_sys_context; select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
COUNT(Y) ---------- 1 SQL_ID 2mgq2mrzd26j6, child number 0 ------------------------------------- select /*+ gather_plan_statistics */ count(y) from t where x = my_package.get_sys_context Plan hash value: 2966233522 ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.38 | 1507 | 1505 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.38 | 1507 | 1505 | |* 2 | TABLE ACCESS FULL| T | 1 | 50001 | 1 |00:00:00.38 | 1507 | 1505 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("X"="MY_PACKAGE"."GET_SYS_CONTEXT"())
It seems optimizer doesn't like SYS_CONTEXT wrapped in a package.
select /*+ gather_plan_statistics */ count(y) from t where x = my_package.get_variable; select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
COUNT(Y) ---------- 1 SQL_ID 4ytd1pqx1yr09, child number 0 ------------------------------------- select /*+ gather_plan_statistics */ count(y) from t where x = my_package.get_variable Plan hash value: 2966233522 ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.16 | 1507 | 1504 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.16 | 1507 | 1504 | |* 2 | TABLE ACCESS FULL| T | 1 | 50001 | 1 |00:00:00.16 | 1507 | 1504 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("X"="MY_PACKAGE"."GET_VARIABLE"())
The optimizer doesn't like the any pl/sql package function, regardless where the value comes from.
To bring it down to an even simpler construction:
CREATE OR REPLACE FUNCTION RETURN_BIND ( BIND_IN IN VARCHAR2 ) RETURN VARCHAR2 AS BEGIN RETURN BIND_IN; END RETURN_BIND; variable b1 varchar2(10) exec :b1 := 'a'; select RETURN_BIND(:b1) from dual; select /*+ gather_plan_statistics */ count(y) from t where x = RETURN_BIND(:b1); select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));
COUNT(Y) ---------- 1 SQL_ID 84y4gdn5tmsb0, child number 0 ------------------------------------- select /*+ gather_plan_statistics */ count(y) from t where x = RETURN_BIND(:b1) Plan hash value: 2966233522 ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.18 | 1507 | 1505 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.18 | 1507 | 1505 | |* 2 | TABLE ACCESS FULL| T | 1 | 50001 | 1 |00:00:00.18 | 1507 | 1505 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("X"="RETURN_BIND"(:B1))
I hope this is enough evidence to claim, there is no bind peeking at the result of any PL/SQL function.
With this in mind, if you care for performance and your data might not be even distributed, take special care if you filter by the return value of any PL/SQL function (or SYS_CONTEXT).
This all was done in an unpatched 12.1 sandbox.
Keine Kommentare:
Kommentar veröffentlichen