Thanks for the question, Jagjeet.
Asked: January 21, 2006 - 11:33 am UTC
Last updated: January 23, 2006 - 12:55 pm UTC
Version: 9.2.0
Viewed 1000+ times
You Asked
Hi,
In this case "set autot on" is telling diff. plan than tkprof
if using bind variables.
SQL> desc big_table
Name Null Type
-------------------------- -------- ----------
R NUMBER
DATA VARCHAR2(300)
SQL> select count(*),r from big_Table group by r;
COUNT(*) R
---------- ----------
49999 1
1 2
I have created index on Big_table ( R )
SQL> exec dbms_stats.gather_Table_Stats(user,'BIG_TABLE',method_opt=>'for all indexed columns',cascade=>true)
PL/SQL procedure successfully completed.
SQL> set autot on exp
Here its showing the correct paln.
===================================
SQL> select count(data) from big_table where r = 1 ;
COUNT(DATA)
-----------
49999
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1556 Card=1 Bytes=100)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'BIG_TABLE' (Cost=1556 Card=49999 Bytes=4999900)
SQL> select count(data) from big_table where r = 2 ;
COUNT(DATA)
-----------
1
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=100)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'BIG_TABLE' (Cost=4 Card=1 Bytes= 100)
3 2 INDEX (RANGE SCAN) OF 'IND_BIG_TABLE' (NON-UNIQUE) (Cost=3 Card= 1)
SQL> var n number
SQL>
SQL> exec :n := 1
PL/SQL procedure successfully completed.
SQL> set autot on
SQL>
SQL> select count(data) from big_Table where r = :n ;
COUNT(DATA)
-----------
49999
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1556 Card=1 Bytes=100)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'BIG_TABLE' (Cost=1556 Card=25000 Bytes=2500000)
Statistics
----------------------------------------------------------
0 db block gets
10024 consistent gets
0 physical read
SQL> exec :n := 2
PL/SQL procedure successfully completed.
SQL> select count(data) from big_Table where r = :n ;
COUNT(DATA)
-----------
1
Execution Plan
---------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1556 Card=1 Bytes=100)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'BIG_TABLE' (Cost=1556 Card=25000 Bytes=2500000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
10024 consistent gets
-- still it is using the same plan with 10024 block gets
-- I have put one space extra before where clause to make
-- it a new statement to hard parse
SQL> select count(data) from big_Table where r = :n ;
COUNT(DATA)
-----------
1
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1556 Card=1 Bytes=100)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'BIG_TABLE' (Cost=1556 Card=25000 Bytes=2500000)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets
Still showing "Full table Scan" but with 4 block gets.
--- From tkprof ---
********************************************************************************
select count(data)
from
big_Table where r = :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 4 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 4 0 1
Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: 23
Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE (cr=4 r=0 w=0 time=202 us)
1 TABLE ACCESS BY INDEX ROWID BIG_TABLE (cr=4 r=0 w=0 time=170 us)
1 INDEX RANGE SCAN IND_BIG_TABLE (cr=3 r=0 w=0 time=118 us)(object id 24087)
********************************************************************************
and Tom said...
tkprof, with the row source operation, shows what actually happens.
explain plan, which cannot:
o bind peek
o know the datatypes of the binds
o reuse a 'soft parse' (eg: it always hard parses)
o understand the optimizer environment in use by the 'real plan' always
can mislead.
for example:
---------------------------------------------------
set echo on
drop table t;
create table t
as
select '99' id, all_objects.*
from all_objects;
update t set id = '1' where rownum = 1;
create index t_idx on t(id);
exec dbms_stats.gather_table_stats( user, 'T', method_opt => 'for all indexed columns' );
variable n varchar2(5)
alter session set sql_trace=true;
set autotrace traceonly statistics
exec :n := '1 '
select * from t t_1 where id = :n;
exec :n := '99'
select * from t t_99 where id = :n;
set autotrace off
-----------------------------------------------
a tkprof with explain=u/p will show:
select * from t t_1 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 4 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.00 0.00 0 4 0 1
Rows Row Source Operation
------- ---------------------------------------------------
1 TABLE ACCESS BY INDEX ROWID T (cr=4 pr=0 pw=0 time=99 us)
1 INDEX RANGE SCAN T_IDX (cr=3 pr=0 pw=0 time=115 us)(object id 57199)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
1 TABLE ACCESS MODE: ANALYZED (FULL) OF 'T' (TABLE)
eh, explain plan <> row source operation...
********************************************************************************
select * from t t_99 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 3311 0.16 0.16 0 3988 0 49648
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3313 0.16 0.16 0 3988 0 49648
Rows Row Source Operation
------- ---------------------------------------------------
49648 TABLE ACCESS FULL T (cr=3988 pr=0 pw=0 time=99473 us)
Rows Execution Plan
------- ---------------------------------------------------
0 SELECT STATEMENT MODE: ALL_ROWS
49648 TABLE ACCESS MODE: ANALYZED (FULL) OF 'T' (TABLE)
row source operation = reality, what actually happened. execution plan = guess based on "incomplete information". explain plan does not bind peek, doesn't have that ability
How about datatypes? Consider:
ops$tkyte@ORA10GR2> create table t
2 as
3 select to_char(object_id) id, all_objects.*
4 from all_objects
5 /
Table created.
ops$tkyte@ORA10GR2> alter table t add constraint t_pk primary key(id);
Table altered.
ops$tkyte@ORA10GR2>
ops$tkyte@ORA10GR2> variable n number
ops$tkyte@ORA10GR2> exec :n := 42
PL/SQL procedure successfully completed.
ops$tkyte@ORA10GR2> set autotrace traceonly
ops$tkyte@ORA10GR2> select * from t where id = :n;
Execution Plan
----------------------------------------------------------
Plan hash value: 1303508680
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 150 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 150 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | T_PK | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=:N)
here, explain plan assumes all binds are strings, it doesn't "see" that in sqlplus we told sqlplus "hey, when you bind, please bind a number" - all it sees is an explain plan command with a :n in it - you don't BIND to explain plans, hence explain plan doesn't know what datatype, or the bind value to peek
Statistics
----------------------------------------------------------
536 recursive calls
0 db block gets
888 consistent gets
0 physical reads
0 redo size
1254 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed
Now, I'm pretty sure that isn't the plan used - 888 IO's to get a single row via a primary key index??
ops$tkyte@ORA10GR2> select * from t where id = 42;
Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 150 | 236 (3)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T | 1 | 150 | 236 (3)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("ID")=42)
see, when we compare a STRING to a NUMBER, we have to conver the string to a number, so there is an implicit function on the database column. That is why we full scan in reality...
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
800 consistent gets
0 physical reads
0 redo size
1254 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed
ops$tkyte@ORA10GR2> set autotrace off
Even if explain plan "peeked" at binds, it would not be good however. Since explain plan hard parsed each time, it would simply show us what would happen if the query was bound with that value and hard parsed - it won't show us what'll really happen.
I suggest you use v$sql_plan or tkprof with row source operation so as to see "reality"
Rating
(2 ratings)
Is this answer out of date? If it is, please let us know via a Comment