Presentation is loading. Please wait.

Presentation is loading. Please wait.

All About Binds Thomas Kyte. All About Binds It’s.

Similar presentations


Presentation on theme: "All About Binds Thomas Kyte. All About Binds It’s."— Presentation transcript:

1 All About Binds Thomas Kyte

2 All About Binds It’s

3 Agenda Performance – Is it just about sharing SQL (or is this really a parsing talk in disguise) Scalability Security Do I always want to bind? What is bind variable peeking? – Is it good or evil in disguise or a bit of both? I’m binding, but it isn’t sharing – what’s up with that? So the developers don't bind is cursor_sharing = force/similar appropriate system wide? What is the real difference between cursor_sharing = force/similar and which should we use under what circumstances?

4 Performance What is involved in a Parse – The “conventional” parse – syntax, semantic check – Optimization (can you spell C.P.U…) – Row Source Generation And then we can finally execute it Conventional parse is fairly lightweight – But it is called a “shared” pool, not “your” pool – Shared data structures have to be protected Optimization can be avoided Row Source Generation can be avoided Bind01.sql

5 ops$tkyte%ORA11GR2> create table t ( x int primary key ); Table created. ops$tkyte%ORA11GR2> create table parse_stats 2 as 3 select a.name, b.value, cast( null as number ) run1, cast(null as number) run2 4 from v$statname a, v$mystat b 5 where a.statistic# = b.statistic# 6 and a.name like 'parse%'; Table created. sqlplus

6 ops$tkyte%ORA11GR2> declare 2 l_cursor sys_refcursor; 3 begin 4 for i in 1.. 10000 5 loop 6 open l_cursor for 'select /* nobind */ * from t where x = ' || i; 7 close l_cursor; 8 end loop; 9 end; 10 / PL/SQL procedure successfully completed. Elapsed: 00:00:11.04 sqlplus

7 Bind01.sql ops$tkyte%ORA11GR2> merge into parse_stats using ( select a.name, b.value new_val 2 from v$statname a, v$mystat b 3 where a.statistic# = b.statistic# 4 and a.name like 'parse%' ) s 5 on (parse_stats.name = s.name) when matched then update set run1 = new_val; 6 rows merged. Elapsed: 00:00:00.15 sqlplus

8 Bind01.sql ops$tkyte%ORA11GR2> declare 2 l_cursor sys_refcursor; 3 begin 4 for i in 1.. 10000 5 loop 6 open l_cursor for 'select /* bind */ * from t where x = :x' using i; 7 close l_cursor; 8 end loop; 9 end; 10 / PL/SQL procedure successfully completed. Elapsed: 00:00:00.73 sqlplus

9 Bind01.sql ops$tkyte%ORA11GR2> merge into parse_stats using ( select a.name, b.value new_val 2 from v$statname a, v$mystat b 3 where a.statistic# = b.statistic# 4 and a.name like 'parse%' ) s 5 on (parse_stats.name = s.name) when matched then update set run2 = new_val; 6 rows merged. Elapsed: 00:00:00.01 sqlplus

10 Bind01.sql ops$tkyte%ORA11GR2> select name, run1, run2, 2 decode( run1, 0, null, 3 to_char(run2/run1*100,'9,999.00') || ' %' ) run2_pct_of_run1 4 from ( 5 select name, run1-value run1, run2-run1 run2 6 from parse_stats 7 ) 8 / NAME RUN1 RUN2 RUN2_PCT_OF ------------------------------ ---------- ---------- ----------- parse time cpu 271 5 1.85 % parse time elapsed 278 9 3.24 % parse count (total) 10078 10018 99.40 % parse count (hard) 10014 3.03 % parse count (failures) 0 0 parse count (describe) 0 0 6 rows selected. sqlplus

11 Performance Wonder if it might affect memory utilization? Strange that count(*) is so low for that first query isn’t it. Unfortunate that sum(sharable_mem) is so high (and remember, it really is many times that amount) Bind02.sql

12 sqlplus ops$tkyte%ORA11GR2> select count(*), to_char(sum(sharable_mem),'999,999,999') sm, 2 to_char(sum(sharable_mem)/ decode( count(*), 0, to_number(null), count(*) ), '999,999,999' ) per_stmt 3 from v$sql 4 where sql_text like 'select /* nobind */ * from t where x = %'; COUNT(*) SM PER_STMT ---------- ------------ ------------ 57 781,917 13,718 ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> select count(*), to_char(sum(sharable_mem),'999,999,999') sm 2 from v$sql 3 where sql_text = 'select /* bind */ * from t where x = :x'; COUNT(*) SM ---------- ------------ 1 13,856

13 sqlplus ops$tkyte%ORA11GR2> declare 2 l_stmt long := 'select /*+ RULE */ * from t where x in ( 1'; 3 l_rec t%rowtype; 4 l_cursor sys_refcursor; 5 begin 6 for i in 2.. 1000 7 loop 8 l_stmt := l_stmt || ', ' || i; 9 end loop; 10 l_stmt := l_stmt || ' ) or x in ( 1'; 11 for i in 1002.. 2000 12 loop 13 l_stmt := l_stmt || ', ' || i; 14 end loop; 15 open l_cursor for l_stmt || ' )'; 16 fetch l_cursor into l_rec; 17 close l_cursor; 18 end; 19 / PL/SQL procedure successfully completed.

14 sqlplus ops$tkyte%ORA11GR2> select count(*), to_char(sum(sharable_mem),'999,999,999') sm 2 from v$sql 3 where sql_text like 'select /*+ RULE */ * from t where x in ( 1%'; COUNT(*) SM ---------- ------------ 1 2,597,091

15 Scalability But it runs fast enough and I’ll buy more memory Does it really? – Run bind03.sql – Review multiuser.sql – Findings coming right up… ops$tkyte@ORA10GR1> select 11/10000 from dual; 11/10000 ----------.0011

16 sqlplus ops$tkyte%ORA11GR2> create table t ( x int primary key ); Table created. ops$tkyte%ORA11GR2> exec dbms_stats.gather_table_stats( user, 'T' ); PL/SQL procedure successfully completed.

17 sqlplus ops$tkyte%ORA11GR2> create or replace procedure nobind 2 as 3 l_cursor sys_refcursor; 4 begin 5 for i in 1.. 2000 6 loop 7 open l_cursor for 'select /* nobind */ * from t where x = ' || i; 8 close l_cursor; 9 end loop; 10 end; 11 / Procedure created.

18 sqlplus ops$tkyte%ORA11GR2> create or replace procedure bind 2 as 3 l_cursor sys_refcursor; 4 begin 5 for i in 1.. 2000 6 loop 7 open l_cursor for 'select /* bind */ * from t where x = :x' using i; 8 close l_cursor; 9 end loop; 10 end; 11 / Procedure created.

19 sqlplus ops$tkyte%ORA11GR2> exec runstats_pkg.rs_start PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> exec nobind PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> exec runstats_pkg.rs_middle PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> exec bind PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> exec runstats_pkg.rs_stop(10000) Run1 ran in 68 hsecs Run2 ran in 8 hsecs run 1 ran in 850% of the time

20 sqlplus Name Run1 Run2 Diff LATCH.kks stats 10,831 33 -10,798 LATCH.shared pool simulator 15,068 63 -15,005 LATCH.row cache objects 48,470 191 -48,279 STAT...session uga memory max 123,452 65,512 -57,940 STAT...session uga memory 65,512 0 -65,512 STAT...session pga memory max 131,072 65,536 -65,536 LATCH.shared pool 87,428 327 -87,101 STAT...session pga memory 65,536 -65,536 -131,072 Run1 latches total versus runs -- difference and pct Run1 Run2 Diff Pct 171,431 1,150 -170,281 14,907.04% PL/SQL procedure successfully completed.

21 Security Google sql injectionsql injection Funny thing happened during my last columnlast column create or replace procedure set_udump (p_udump in varchar2) as begin execute immediate 'alter system set user_dump_dest = '''||p_udump||''' scope=memory'; end; /

22 Security Google sql injectionsql injection Funny thing happened during my last columnlast column create or replace procedure set_udump (p_udump in varchar2) as begin execute immediate 'alter system set user_dump_dest = '''||p_udump||''' scope=memory'; end; / begin set_udump('C:\ORA4\admin\ora4\udump2'' scope=memory utl_file_dir=''*'' scope=spfile user_dump_dest=''C:\ORA4\admin\ora4\udump2'); end;

23 Security Google sql injectionsql injection Funny thing happened during my last columnlast column create or replace procedure set_udump (p_udump in varchar2) as begin if ( p_udump NOT LIKE '%=%' ) then execute immediate 'alter system set user_dump_dest = '''||p_udump||''' scope=memory'; else raise_application_error(-20000,'Sorry, but for safety reasons this procedure does not allow "=" in the parameter value'); end if; end; inj.sql

24 sqlplus ops$tkyte%ORA11GR2> create or replace procedure inj( p_date in date ) 2 as 3 l_rec all_users%rowtype; 4 c sys_refcursor; 5 l_query long; 6 begin 7 l_query := ' 8 select * 9 from all_users 10 where created = ''' ||p_date ||''''; 11 12 dbms_output.put_line( l_query ); 13 open c for l_query; 14 15 for i in 1.. 5 16 loop 17 fetch c into l_rec; 18 exit when c%notfound; 19 dbms_output.put_line( l_rec.username || '.....' ); 20 end loop; 21 close c; 22 end; 23 / Procedure created.

25 sqlplus ops$tkyte%ORA11GR2> exec inj( sysdate ) select * from all_users where created = '25-OCT-10' PL/SQL procedure successfully completed.

26 sqlplus ops$tkyte%ORA11GR2> alter session set 2 nls_date_format = 'dd-mon-yyyy"'' or ''a'' = ''a"'; Session altered.

27 sqlplus ops$tkyte%ORA11GR2> exec inj( sysdate ) select * from all_users where created = '25-oct-2010' or 'a' = 'a' C..... B..... A..... FB_DEMO..... BIG_TABLE..... PL/SQL procedure successfully completed.

28 Do I always want to bind? Always say “Never say Never” Never say “Always” I always say… You do not want to – Over Bind – Always Bind – Why….

29 Do I always want to bind? Over Binding – Compulsive disorder to eradicate all literals in SQL – Brought on by taking good advice to an illogical extreme – Do we need to bind those? – Might it be a bad thing to bind those? Begin for x in ( select object_name from user_objects where object_type in ( ‘TABLE’, ‘INDEX’ )) loop …

30 Do I always want to bind? Always Binding – Data warehouse – no way. – When you run queries per second, yes. – When you run queries that take seconds, maybe, maybe no. Consider the frequency of the query o5,000 users running reports. Bind o50 users data mining. No Bind oOLTP. Bind oEnd of month report. Maybe No Bind. oCommon Sense, it is all about math

31 Bind Variable Peeking It is good or pure evil in disguise (neither of course) Introduced in 9i Release 1 Makes the first hard parse of: Optimize as if you submitted: What are the assumptions then by the implementer of this feature. Select * from emp where empno = :X; Select * from emp where empno = 1234; bvp01.sql

32 sqlplus ops$tkyte%ORA11GR2> create table t 2 as 3 select 99 id, a.* 4 from stage a 5 where rownum <= 20000; Table created. ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> update t set id = 1 where rownum = 1; 1 row updated. ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> create index t_idx on t(id); Index created.

33 sqlplus ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', 4 method_opt=>'for all indexed columns size 254', 5 estimate_percent => 100, 6 cascade=>TRUE ); 7 end; 8 / PL/SQL procedure successfully completed.

34 sqlplus ops$tkyte%ORA11GR2> set autotrace traceonly explain ops$tkyte%ORA11GR2> select count(object_type) from t where id = 1; Execution Plan ---------------------------------------------------------- Plan hash value: 1789076273 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 14 | 2 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 14 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 14 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"=1) ops$tkyte%ORA11GR2> set autotrace off

35 sqlplus ops$tkyte%ORA11GR2> set autotrace traceonly explain ops$tkyte%ORA11GR2> select count(object_type) from t where id = 99; Execution Plan ---------------------------------------------------------- Plan hash value: 2966233522 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 14 | 82 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 14 | | | |* 2 | TABLE ACCESS FULL| T | 19999 | 273K| 82 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"=99) ops$tkyte%ORA11GR2> set autotrace off

36 sqlplus ops$tkyte%ORA11GR2> variable n number ops$tkyte%ORA11GR2> exec :n := 1 PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> explain plan for 2 select count(object_type) from t n_is_1_first where id = :n; Explained. ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------- Plan hash value: 2966233522 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 14 | 82 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 14 | | | |* 2 | TABLE ACCESS FULL| T | 10000 | 136K| 82 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"=TO_NUMBER(:N)) 14 rows selected.

37 sqlplus ops$tkyte%ORA11GR2> alter session set events '10046 trace name context forever, level 12'; Session altered. ops$tkyte%ORA11GR2> select count(object_type) from t n_is_1_first where id = :n; COUNT(OBJECT_TYPE) ------------------ 1

38 sqlplus ops$tkyte%ORA11GR2> exec :n := 99 PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> select count(object_type) from t n_is_1_first where id = :n; COUNT(OBJECT_TYPE) ------------------ 19999

39 sqlplus ops$tkyte%ORA11GR2> select count(object_type) from t n_is_99_first where id = :n; COUNT(OBJECT_TYPE) ------------------ 19999

40 sqlplus ops$tkyte%ORA11GR2> select count(object_type) from t n_is_99_first where id = :n; COUNT(OBJECT_TYPE) ------------------ 1

41 sqlplus select count(object_type) from t n_is_1_first where id = :n call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.07 0 0 0 0 Fetch 2 0.00 0.02 0 3 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.09 0 3 0 1 Misses in library cache during parse: 1 Misses in library cache during execute: 1 Optimizer mode: ALL_ROWS Parsing user id: 211 (OPS$TKYTE) Rows Row Source Operation ------- --------------------------------------------------- 1 SORT AGGREGATE (cr=3 pr=0 pw=0 time=0 us) 1 TABLE ACCESS BY INDEX ROWID T (cr=3 pr=0 pw=0 time=0 us cost=2 size=14 card=1) 1 INDEX RANGE SCAN T_IDX (cr=2 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 88040) Rows Execution Plan ------- --------------------------------------------------- 0 SELECT STATEMENT MODE: ALL_ROWS 1 SORT (AGGREGATE) 1 TABLE ACCESS MODE: ANALYZED (FULL) OF 'T' (TABLE)

42 sqlplus select count(object_type) from t n_is_1_first where id = :n call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.01 0 322 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.01 0 322 0 1 Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 211 (OPS$TKYTE) Rows Row Source Operation ------- --------------------------------------------------- 1 SORT AGGREGATE (cr=322 pr=0 pw=0 time=0 us) 19999 TABLE ACCESS BY INDEX ROWID T (cr=322 pr=0 pw=0 time=76043 us cost=2 size=14 card=1) 19999 INDEX RANGE SCAN T_IDX (cr=41 pr=0 pw=0 time=25984 us cost=1 size=0 card=1)(object id 88040) Rows Execution Plan ------- --------------------------------------------------- 0 SELECT STATEMENT MODE: ALL_ROWS 1 SORT (AGGREGATE) 19999 TABLE ACCESS MODE: ANALYZED (FULL) OF 'T' (TABLE)

43 sqlplus select count(object_type) from t n_is_99_first where id = :n call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 285 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 285 0 1 Misses in library cache during parse: 1 Misses in library cache during execute: 1 Optimizer mode: ALL_ROWS Parsing user id: 211 (OPS$TKYTE) Rows Row Source Operation ------- --------------------------------------------------- 1 SORT AGGREGATE (cr=285 pr=0 pw=0 time=0 us) 19999 TABLE ACCESS FULL T (cr=285 pr=0 pw=0 time=24838 us cost=82 size=279986 card=19999) Rows Execution Plan ------- --------------------------------------------------- 0 SELECT STATEMENT MODE: ALL_ROWS 1 SORT (AGGREGATE) 19999 TABLE ACCESS MODE: ANALYZED (FULL) OF 'T' (TABLE)

44 sqlplus select count(object_type) from t n_is_99_first where id = :n call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 285 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.00 0 285 0 1 Misses in library cache during parse: 0 Optimizer mode: ALL_ROWS Parsing user id: 211 (OPS$TKYTE) Rows Row Source Operation ------- --------------------------------------------------- 1 SORT AGGREGATE (cr=285 pr=0 pw=0 time=0 us) 1 TABLE ACCESS FULL T (cr=285 pr=0 pw=0 time=0 us cost=82 size=279986 card=19999) Rows Execution Plan ------- --------------------------------------------------- 0 SELECT STATEMENT MODE: ALL_ROWS 1 SORT (AGGREGATE) 1 TABLE ACCESS MODE: ANALYZED (FULL) OF 'T' (TABLE)

45 Bind Variable Peeking Adaptive Cursor Sharing – New in 11gR1 – Will help solve most bind variable peeking issues – Works currently with equality and range operations (but not “like” predicates) bvp03.sql

46 sqlplus ops$tkyte%ORA11GR2> create table t 2 as 3 select 99 id, a.* 4 from stage a 5 where rownum <= 20000; Table created. ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> update t set id = 1 where rownum = 1; 1 row updated. ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> create index t_idx on t(id); Index created.

47 sqlplus ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', 4 method_opt=>'for all indexed columns size 254', 5 estimate_percent => 100, 6 cascade=>TRUE ); 7 end; 8 / PL/SQL procedure successfully completed.

48 sqlplus ops$tkyte%ORA11GR2> exec :n := 1; PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> select /*BVP03*/ count(subobject_name) from t where id = :n; COUNT(SUBOBJECT_NAME) --------------------- 0 ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT ----------------------- SQL_ID 4un62u0uttg6u, child number 0 ------------------------------------- select /*BVP03*/ count(subobject_name) from t where id = :n Plan hash value: 1789076273 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 20 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 20 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"=:N) 20 rows selected.

49 sqlplus ops$tkyte%ORA11GR2> select child_number, executions, buffer_gets, 2 is_bind_sensitive, is_bind_aware 3 from v$sql 4 where sql_text like 'select /*BVP03*/ %'; CHILD_NUMBER EXECUTIONS BUFFER_GETS IS_BIND_SENSITIVE IS_BIND_AWARE ------------ ---------- ----------- ------------------ --------------- 0 1 3 Y N

50 sqlplus ops$tkyte%ORA11GR2> exec :n := 99; PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> select /*BVP03*/ count(subobject_name) from t where id = :n; COUNT(SUBOBJECT_NAME) --------------------- 118 ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT ----------------------------------------- SQL_ID 4un62u0uttg6u, child number 0 ------------------------------------- select /*BVP03*/ count(subobject_name) from t where id = :n Plan hash value: 1789076273 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 20 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 20 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"=:N) 20 rows selected.

51 sqlplus ops$tkyte%ORA11GR2> select child_number, executions, buffer_gets, 2 is_bind_sensitive, is_bind_aware 3 from v$sql 4 where sql_text like 'select /*BVP03*/ %'; CHILD_NUMBER EXECUTIONS BUFFER_GETS IS_BIND_SENSITIVE IS_BIND_AWARE ------------ ---------- ----------- ------------------ --------------- 0 2 325 Y N

52 sqlplus ops$tkyte%ORA11GR2> select /*BVP03*/ count(subobject_name) from t where id = :n; COUNT(SUBOBJECT_NAME) --------------------- 118 ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT ------------------------- SQL_ID 4un62u0uttg6u, child number 1 ------------------------------------- select /*BVP03*/ count(subobject_name) from t where id = :n Plan hash value: 2966233522 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 82 (100)| | | 1 | SORT AGGREGATE | | 1 | 20 | | | |* 2 | TABLE ACCESS FULL| T | 19999 | 390K| 82 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"=:N) 19 rows selected.

53 sqlplus ops$tkyte%ORA11GR2> select child_number, executions, buffer_gets, 2 is_bind_sensitive, is_bind_aware 3 from v$sql 4 where sql_text like 'select /*BVP03*/ %'; CHILD_NUMBER EXECUTIONS BUFFER_GETS IS_BIND_SENSITIVE IS_BIND_AWARE ------------ ---------- ----------- ------------------ --------------- 0 2 325 Y N 1 1 285 Y Y

54 sqlplus ops$tkyte%ORA11GR2> exec :n := 1 PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> select /*BVP03*/ count(subobject_name) from t where id = :n; COUNT(SUBOBJECT_NAME) --------------------- 0 ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT --------------------------- SQL_ID 4un62u0uttg6u, child number 2 ------------------------------------- select /*BVP03*/ count(subobject_name) from t where id = :n Plan hash value: 1789076273 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 20 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 1 | 20 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_IDX | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"=:N) 20 rows selected.

55 sqlplus ops$tkyte%ORA11GR2> select child_number, executions, buffer_gets, 2 is_bind_sensitive, is_bind_aware 3 from v$sql 4 where sql_text like 'select /*BVP03*/ %'; CHILD_NUMBER EXECUTIONS BUFFER_GETS IS_BIND_SENSITIVE IS_BIND_AWARE ------------ ---------- ----------- ------------------ --------------- 0 2 325 Y N 1 1 285 Y Y 2 1 3 Y Y

56 Bind Variable Peeking over time 8i and before – no peeking 9i, 10g – Peeking – First plan “wins” 11g and above – Adaptive Cursor Sharing

57 Bind Variable Peeking What can you do when those assumptions don’t hold true for you in a specific case? – 11gR1 and above!! – Don’t bind that query, that is a possibility. Do the math … – Don’t use histograms Get the “general plan” Consistent Plan, but typically not the “best” plan for all – Use your domain knowledge Input dates within the last month – use this query, else use that query Codes less than 50 – use this query, else use that query Status values of ‘A’, ‘M’ and ‘N’ …. Else…. – Cursor_sharing = similar – You can disable it – but that is like “don’t use histograms” in a system that uses binds.

58 I’m binding, but it isn’t sharing Many things can do that – Any environmental variables that affect the optimizer – Or security (this is why PLSQL rules) – Bind Type mismatch – Language – PLSQL compiler switches For example, lets tune with SQL_TRACE=TRUE And Look deeper at “bind mismatches” Desc v$sql_shared_cursor tune.sql Bindmis.sql

59 sqlplus ops$tkyte%ORA11GR2> alter session set "_optimizer_extended_cursor_sharing_rel"=none; Session altered. ops$tkyte%ORA11GR2> create table t 2 as 3 select 99 id, a.* 4 from stage a 5 where rownum <= 20000; Table created. ops$tkyte%ORA11GR2> update t set id = 1 where rownum = 1; 1 row updated. ops$tkyte%ORA11GR2> create index t_idx on t(id); Index created.

60 sqlplus ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'T', 4 method_opt => 'for all indexed columns size 254', 5 estimate_percent => 100, 6 cascade=> true); 7 end; 8 / PL/SQL procedure successfully completed.

61 sqlplus ops$tkyte%ORA11GR2> variable n number ops$tkyte%ORA11GR2> exec :n := 99 PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> set autotrace traceonly statistics ops$tkyte%ORA11GR2> select * from t where id = :n; 19999 rows selected. Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 1601 consistent gets 0 physical reads 0 redo size 928023 bytes sent via SQL*Net to client 15082 bytes received via SQL*Net from client 1335 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 19999 rows processed ops$tkyte%ORA11GR2> set autotrace off

62 sqlplus ops$tkyte%ORA11GR2> exec :n := 1 PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> set autotrace traceonly statistics ops$tkyte%ORA11GR2> select * from t where id = :n; Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 286 consistent gets 0 physical reads 0 redo size 1448 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed ops$tkyte%ORA11GR2> set autotrace off

63 sqlplus ops$tkyte%ORA11GR2> alter session set events '10046 trace name context forever, level 12'; Session altered. ops$tkyte%ORA11GR2> select * from t where id = :n; Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 1448 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

64 sqlplus ops$tkyte%ORA11GR2> alter session set events '10046 trace name context off'; Session altered. ops$tkyte%ORA11GR2> select * from t where id = :n; Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 286 consistent gets 0 physical reads 0 redo size 1448 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

65 sqlplus ops$tkyte%ORA11GR2> alter session set events '10046 trace name context forever, level 12'; Session altered. ops$tkyte%ORA11GR2> select * from t where id = :n; Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 1448 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

66 sqlplus ops$tkyte%ORA11GR2> alter session set events '10046 trace name context off'; Session altered. ops$tkyte%ORA11GR2> select * from t where id = :n; Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 286 consistent gets 0 physical reads 0 redo size 1448 bytes sent via SQL*Net to client 419 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed

67 sqlplus ops$tkyte%ORA11GR2> select parsing_user_id puid, parsing_schema_id psid, is_bind_aware, is_bind_sensitive, 2 address, child_address 3 from v$sql 4 where sql_text = 'select * from t where id = :n'; PUID PSID IS_BIND_AWARE IS_BIND_SENSITIVE ADDRESS CHILD_AD ---------- ---------- --------------- ------------------ -------- -------- 211 211 N N 32448F98 2D55B0B0 211 211 N N 32448F98 3245FF8C

68 sqlplus ops$tkyte%ORA11GR2> alter session set "_optimizer_extended_cursor_sharing_rel"=simple; Session altered.

69 sqlplus ops$tkyte%ORA11GR2> create table t ( x varchar2(2000) ); Table created.

70 sqlplus ops$tkyte%ORA11GR2> declare 2 a varchar2(1) := 'x'; 3 b varchar2(100) := rpad('x',100,'x'); 4 c varchar2(500) := rpad('x',500,'x'); 5 d varchar2(1000) := rpad('x',1000,'x'); 6 begin 7 insert into t values(a); 8 insert into t values(b); 9 insert into t values(c); 10 insert into t values(d); 11 end; 12 / PL/SQL procedure successfully completed.

71 sqlplus ops$tkyte%ORA11GR2> select parsing_user_id puid, parsing_schema_id psid, 2 sql_text, address, child_address 3 from v$sql 4 where sql_text like 'INSERT%INTO%T%VALUES(%:B1%)' 5 / PUID PSID SQL_TEXT ADDRESS CHILD_AD ---------- ---------- ------------------------------ -------- -------- 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2D77BDF8 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 325BFA18 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2C284A44

72 sqlplus ops$tkyte%ORA11GR2> select * 2 from v$sql_shared_cursor 3 where address = '&ADDR' 4 / old 3: where address = '&ADDR' new 3: where address = '325F10B8' SQL_ID ADDRESS CHILD_AD CHILD_NUMBER U S O O S L F E B P I S T A B D L T B I I R L I O E M U T N F A I T D L D B ------------- -------- -------- ------------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - P C S C P T M B M R O P M F L P L A F L R L H P B - - - - - - - - - - - - - - - - - - - - - - - - - 9bay73nakuyw9 325F10B8 2D77BDF8 0 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 9bay73nakuyw9 325F10B8 325BFA18 1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N Y 9bay73nakuyw9 325F10B8 2C284A44 2 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N Y

73 sqlplus ops$tkyte%ORA11GR2> select bind_mismatch, BIND_LENGTH_UPGRADEABLE 2 from v$sql_shared_cursor 3 where address = '&ADDR' 4 / old 3: where address = '&ADDR' new 3: where address = '325F10B8' B - N N Y

74 sqlplus ops$tkyte%ORA11GR2> declare 2 a varchar2(1) := 'x'; 3 b varchar2(10) := rpad('x',10,'x'); 4 c varchar2(20) := rpad('x',20,'x'); 5 d varchar2(30) := rpad('x',30,'x'); 6 begin 7 insert into t xxx values(a); 8 insert into t xxx values(b); 9 insert into t xxx values(c); 10 insert into t xxx values(d); 11 end; 12 / PL/SQL procedure successfully completed.

75 sqlplus ops$tkyte%ORA11GR2> select parsing_user_id puid, parsing_schema_id psid, 2 sql_text, address, child_address 3 from v$sql 4 where sql_text like 'INSERT%INTO%T%VALUES(%:B1%)' 5 / PUID PSID SQL_TEXT ADDRESS CHILD_AD ---------- ---------- ------------------------------ -------- -------- 211 211 INSERT INTO T XXX VALUES(:B1 ) 2D4C7DEC 2C33D5A4 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2D77BDF8 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 325BFA18 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2C284A44

76 sqlplus ops$tkyte%ORA11GR2> declare 2 a varchar2(1) := 'x'; 3 b varchar2(10) := rpad('x',10,'x'); 4 c varchar2(32) := rpad('x',32,'x'); 5 d varchar2(33) := rpad('x',33,'x'); 6 begin 7 insert into t yyy values(a); 8 insert into t yyy values(b); 9 insert into t yyy values(c); 10 insert into t yyy values(d); 11 end; 12 / PL/SQL procedure successfully completed.

77 sqlplus ops$tkyte%ORA11GR2> select parsing_user_id puid, parsing_schema_id psid, 2 sql_text, address, child_address 3 from v$sql 4 where sql_text like 'INSERT%INTO%T%VALUES(%:B1%)' 5 / PUID PSID SQL_TEXT ADDRESS CHILD_AD ---------- ---------- ------------------------------ -------- -------- 211 211 INSERT INTO T YYY VALUES(:B1 ) 2D55EF40 2C1E7E8C 211 211 INSERT INTO T YYY VALUES(:B1 ) 2D55EF40 32474080 211 211 INSERT INTO T XXX VALUES(:B1 ) 2D4C7DEC 2C33D5A4 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2D77BDF8 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 325BFA18 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2C284A44 6 rows selected.

78 sqlplus ops$tkyte%ORA11GR2> declare 2 a varchar2(1) := 'x'; 3 b varchar2(100) := rpad('x',100,'x'); 4 c varchar2(500) := rpad('x',500,'x'); 5 d varchar2(1000) := rpad('x',1000,'x'); 6 begin 7 insert into t zzz values(d); 8 insert into t zzz values(c); 9 insert into t zzz values(b); 10 insert into t zzz values(a); 11 end; 12 / PL/SQL procedure successfully completed.

79 sqlplus ops$tkyte%ORA11GR2> select parsing_user_id puid, parsing_schema_id psid, 2 sql_text, address, child_address 3 from v$sql 4 where sql_text like 'INSERT%INTO%T%VALUES(%:B1%)' 5 / PUID PSID SQL_TEXT ADDRESS CHILD_AD ---------- ---------- ------------------------------ -------- -------- 211 211 INSERT INTO T YYY VALUES(:B1 ) 2D55EF40 2C1E7E8C 211 211 INSERT INTO T YYY VALUES(:B1 ) 2D55EF40 32474080 211 211 INSERT INTO T XXX VALUES(:B1 ) 2D4C7DEC 2C33D5A4 211 211 INSERT INTO T ZZZ VALUES(:B1 ) 2D5ECF98 2D52AFD0 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2D77BDF8 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 325BFA18 211 211 INSERT INTO T VALUES(:B1 ) 325F10B8 2C284A44 7 rows selected.

80 Cursor Sharing So the developers don't bind is cursor_sharing = force/similar appropriate system wide? No

81 Cursor Sharing Negatively Impacts Well Written Applications – They run slower even if plans do not change – We just did bind variable peeking, so we know about Over binding (this is over binding defined) Always binding (this is always binding defined) – Possible plan changes Optimizer has less information, doesn’t have the facts – Behavior Changes Don’t know column widths anymore Don’t know scale/precision anymore cs01.sql

82 sqlplus ops$tkyte%ORA11GR2> alter session set cursor_sharing=exact; Session altered. ops$tkyte%ORA11GR2> create table t 2 as 3 select * 4 from all_users 5 where rownum = 1; Table created.

83 sqlplus ops$tkyte%ORA11GR2> alter session set cursor_sharing=exact; Session altered. ops$tkyte%ORA11GR2> select substr(username,1,10) uname, 2 to_char(user_id,'999,999') u_id, 3 to_char(created,'Dy Mon DD, YYYY' ) created 4 from t cs_exact; UNAME U_ID CREATED ---------- -------- ---------------- SYS 0 Thu Aug 13, 2009

84 sqlplus ops$tkyte%ORA11GR2> alter session set cursor_sharing=force; Session altered. ops$tkyte%ORA11GR2> select substr(username,1,10) uname, 2 to_char(user_id,'999,999') u_id, 3 to_char(created,'Dy Mon DD, YYYY' ) created 4 from t cs_force; UNAME ------------------------------ U_ID ----------------------------------------------------------------------- -------------------------------------------------- CREATED ----------------------------------------------------------------------- ---- SYS 0 Thu Aug 13, 2009

85 sqlplus ops$tkyte%ORA11GR2> alter session set cursor_sharing=exact; Session altered. ops$tkyte%ORA11GR2> column sql_text format a80 ops$tkyte%ORA11GR2> select sql_text 2 from v$sql 3 where sql_text like 'select substr(username%'; SQL_TEXT -------------------------------------------------------------------------------- select substr(username,1,10) uname, to_char(user_id,'999,999') u_id, to_char(created,'Dy Mon DD, YYYY' ) created from t cs_exact select substr(username,:"SYS_B_0",:"SYS_B_1") uname, to_char(user_id,:"SY S_B_2") u_id, to_char(created,:"SYS_B_3" ) created from t cs_force

86 Force/Similar Force is just that – All literals, without any regard to anything, will be replaced with binds – 10g and before - There will be probably one plan generated (all things considered the same! Remember v$sql_shared_cursor) Consider the bind variable peeking implications oCold start, first query is id=99 oCold start, first query is id=1 oBouncing the database is my tuning tool? – But, things change… 11gR1 and up

87 Force/Similar Similar – When replacing the bind with a literal ( reversed purposely ) could change the plan… – Multiple child cursors will be developed – Each can have it’s own unique plan – Optimization will use the “best” plan – Is this better than force? Depends More child cursors Longer code path – But is does solve a little more of the problem. similar.sql

88 sqlplus ops$tkyte%ORA11GR2> create table emp as select * from scott.emp; Table created. ops$tkyte%ORA11GR2> update emp set deptno = 99; 14 rows updated. ops$tkyte%ORA11GR2> begin 2 for i in 1.. 11 3 loop 4 insert /*+ append */ into emp select * from emp; 5 commit; 6 end loop; 7 end; 8 / PL/SQL procedure successfully completed. ops$tkyte%ORA11GR2> select count(*) from emp; COUNT(*) ---------- 28672

89 sqlplus ops$tkyte%ORA11GR2> update emp set deptno = 1 where rownum = 1; 1 row updated. ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> create index dept_idx on emp(deptno); Index created. ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> begin 2 dbms_stats.gather_table_stats 3 ( user, 'EMP', 4 method_opt=>'for all indexed columns', 5 estimate_percent => 100, 6 cascade=>true ); 7 end; 8 / PL/SQL procedure successfully completed.

90 sqlplus ops$tkyte%ORA11GR2> select count(empno) from emp where deptno = 99; Execution Plan ---------------------------------------------------------- Plan hash value: 2083865914 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 53 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 16 | | | |* 2 | TABLE ACCESS FULL| EMP | 28671 | 447K| 53 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("DEPTNO"=99)

91 sqlplus ops$tkyte%ORA11GR2> select count(empno) from emp where deptno = 1; Execution Plan ---------------------------------------------------------- Plan hash value: 237848182 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 2 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 16 | | | | 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 16 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | DEPT_IDX | 1 | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DEPTNO"=1)

92 sqlplus ops$tkyte%ORA11GR2> alter session set events '10046 trace name context forever, level 12'; Session altered. ops$tkyte%ORA11GR2> alter session set cursor_sharing=similar; Session altered.

93 sqlplus ops$tkyte%ORA11GR2> select count(empno) from emp CSS where deptno = 1; COUNT(EMPNO) ------------ 1 ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------------------------- --------------------- SQL_ID 93pjrvfdz49m5, child number 0 ------------------------------------- select count(empno) from emp CSS where deptno = :"SYS_B_0" Plan hash value: 237848182 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | | 1 | SORT AGGREGATE | | 1 | 16 | | | | 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 16 | 2 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | DEPT_IDX | 1 | | 1 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("DEPTNO"=:SYS_B_0) 20 rows selected.

94 sqlplus ops$tkyte%ORA11GR2> select count(empno) from emp CSS where deptno = 99; COUNT(EMPNO) ------------ 28671 ops$tkyte%ORA11GR2> select * from table(dbms_xplan.display_cursor); PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------------------------- --------------------- SQL_ID 93pjrvfdz49m5, child number 1 ------------------------------------- select count(empno) from emp CSS where deptno = :"SYS_B_0" Plan hash value: 2083865914 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 53 (100)| | | 1 | SORT AGGREGATE | | 1 | 16 | | | |* 2 | TABLE ACCESS FULL| EMP | 28671 | 447K| 53 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("DEPTNO"=:SYS_B_0) 19 rows selected.

95 sqlplus ops$tkyte%ORA11GR2> alter session set cursor_sharing=exact; Session altered. ops$tkyte%ORA11GR2> select sql_text, is_bind_aware, is_bind_sensitive from v$sql 2 where sql_text like 'select count(empno) from emp CSS where deptno =%'; SQL_TEXT IS_BIND_AWARE IS_BIND_SENSITIVE ---------------------------------------- --------------- -------------- ---- select count(empno) from emp CSS where d N Y eptno = :"SYS_B_0" select count(empno) from emp CSS where d N Y eptno = :"SYS_B_0"

96 Force/Similar In Short, in 10g and before just say No To setting at the system level, this is an application level bug “workaround until we get it fixed for real” tool

97 Questions


Download ppt "All About Binds Thomas Kyte. All About Binds It’s."

Similar presentations


Ads by Google