Here is an execution plan that served as a path for the Oracle SQL engine to execute a simple two table join
SQL> SELECT count(t1.small_vc) ,count(t2.padding) FROM t1, t2 WHERE t1.id1 = t2.id ; SQL> start xstat SQL_ID b5yc4wnt59bxn, child number 0 ------------------------------------- -------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 | | 1 | SORT AGGREGATE | | 1 | 1 | 1 | | 2 | NESTED LOOPS | | 1 | | 10 | | 3 | NESTED LOOPS | | 1 | 10 | 10 | | 4 | TABLE ACCESS FULL | T2 | 1 | 10 | 10 | |* 5 | INDEX UNIQUE SCAN | T1_PK | 10 | 1 | 10 | | 6 | TABLE ACCESS BY INDEX ROWID| T1 | 10 | 1 | 10 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("T1"."ID1"="T2"."ID") Note ----- - dynamic sampling used for this statement (level=2)
What does this last Note about dynamic sampling imply?
That involved tables have stale statistics?
No it doesn’t imply such a conclusion
That involved tables have no statistics at all?
No it doesn’t exactly imply such a conclusion
The above Note indicates that at least one (particularly for the default level 2) of the involved tables in the above query has no statistics at all. It doesn’t mean as well that all tables in the join query have no statistics. It means that at least one of the two tables has been NOT ANALYZED using the 10053 trace file terminology as shown below:
*************************************** BASE STATISTICAL INFORMATION *************************************** Table Stats:: Table: T2 Alias: T2 (NOT ANALYZED) --- spot this #Rows: 327 #Blks: 4 AvgRowLen: 100.00 ChainCnt: 0.00 Column (#1): ID( NO STATISTICS (using defaults) AvgLen: 13 NDV: 10 Nulls: 0 Density: 0.097859 Index Stats:: Index: T2_I_FK Col#: 1 LVLS: 0 #LB: 1 #DK: 10 LB/K: 1.00 DB/K: 1.00 CLUF: 1.00 ***********************
In fact, what I did not show you is the model I’ve used which is
create table t1 as select rownum id1, trunc(dbms_random.value(1,1000)) id2, lpad(rownum,10,'0') small_vc, rpad('x',1000) padding from dual connect by level <= 1e4; alter table t1 add constraint t1_pk primary key (id1); create index t1_i1 on t1(id2); create table t2 as select * from ( select rownum as id ,mod(t1.id1,5) + mod(rownum,10)* 10 as id1 ,lpad(rownum,10,'0') as small_vc ,rpad('x',70) as padding from t1 where rownum <= 10 ) order by id1; alter table t2 add constraint t2_fk foreign key(id) references t1(id1); create index t2_i_fk on t2(id);
And most importantly the statistics I have collected for table t1 only
BEGIN dbms_stats.gather_table_stats(USER ,'t1' ,method_opt => 'FOR ALL COLUMNS SIZE 1' ,estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE ,CASCADE => true); END; /
The CBO 10053 trace file echoes for table t1, in contrast to t2 table on which I haven’t collected statistics, the following lines which indicate that the CBO has used table t1 corresponding dictionary statistics during the execution plan compilation time
*********************** Table Stats:: Table: T1 Alias: T1 #Rows: 10000 #Blks: 1460 AvgRowLen: 1020.00 ChainCnt: 0.00 Column (#1): ID1( AvgLen: 4 NDV: 10000 Nulls: 0 Density: 0.000100 Min: 1 Max: 10000 Index Stats:: Index: T1_I1 Col#: 2 LVLS: 1 #LB: 21 #DK: 999 LB/K: 1.00 DB/K: 9.00 CLUF: 9968.00 Index: T1_PK Col#: 1 LVLS: 1 #LB: 20 #DK: 10000 LB/K: 1.00 DB/K: 1.00 CLUF: 1429.00 Access path analysis for T1 *************************************** SINGLE TABLE ACCESS PATH Single Table Cardinality Estimation for T1[T1] Table: T1 Alias: T1 Card: Original: 10000.000000 Rounded: 10000 Computed: 10000.00 Non Adjusted: 10000.00 Access Path: TableScan Cost: 447.51 Resp: 447.51 Degree: 0 Cost_io: 439.00 Cost_cpu: 12297302 Resp_io: 439.00 Resp_cpu: 12297302 Best:: AccessPath: TableScan Cost: 447.51 Degree: 1 Resp: 447.51 Card: 10000.00 Bytes: 0
Bottom line: when you see a Note about dynamic sampling at level 2 in an execution plan then bear in mind that this Note doesn’t imply that all tables involved in the underlying query have no statistics. It indicates that there is at least one table without statistics.
I’ve also attached to this blog the corresponding documentation about dynamic (statistics) sampling