验证表统计信息是否不对

表统计信息的收集时间可以从user_table的analylize_time中得知,但是统计信息是否准确,还是不好判断,上课中郭老师提出了采用dbms_xplan.display_cursor查看收集的信息可以帮助我们判断统计信息是否陈旧。

如下是具体的操作方式:

SQL> set linesize 1000

SQL> Set pagesize 100

SQL> drop table test1 purge;

表已删除。

SQL> drop table test2 purge;

表已删除。

SQL> create table test1 as select * from dba_objects where rownum <=100;

表已创建。

SQL> create table test2 as select * from dba_objects where rownum <=1000;

表已创建。

-- statistics_level有三个值,basic,typical,all。如果为basic则关闭所有性能数据的收集;如果是typical,除了plan_executetion_statistics和OS statistics不能收集,其他都能收集;all即都收集。

--statistics_level设为all,收集所有信息

SQL> alter session set statistics_level=all;

会话已更改。

--采用hint让其不要动态收集统计信息(一般统计信息没收集过的表在执行sql时会动态收集)

SQL> select /*+Dynamic_sampling(0)*/count(*)

  2    from test1 t1, test2 t2

  3   where t1.object_id = t2.object_id;

  COUNT(*)

----------

       100

--查看最新收集的信息(dbms_xplan.display_cursor)

SQL> SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last'));

PLAN_TABLE_OUTPUT

---------------------------------------------------------

SQL_ID  55ga693yggjkd, child number 0

-------------------------------------

select /*+Dynamic_sampling(0)*/count(*)   from test1 t1, test2 t2

where t1.object_id = t2.object_id

Plan hash value: 2544416891

---------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |          |        1 |             |          1 |00:00:00.06 |      20 |     15 |             |            |          |
|   1 |  SORT AGGREGATE     |          |        1 |         1  |          1 |00:00:00.06 |      20 |     15 |             |             |          |
|*  2 |   HASH JOIN               |          |        1 |    1307 |       100 |00:00:00.06 |      20 |     15 |  1517K  |  1517K | 1260K (0)|
|   3 |    TABLE ACCESS FULL| TEST1 |       1 |      409 |       100 |00:00:00.06 |       4 |        2 |             |            |          |
|   4 |    TABLE ACCESS FULL| TEST2 |       1 |    1307 |      1000 |00:00:00.01 |      16 |     13 |             |            |          |
---------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

已选择22行。

 如上信息可以看到,表信息在没收集的情况下,e-rows(评估的行数)和a-rows(实际行数)存在很大的差距。

--对表进行手动收集统计信息

SQL> exec dbms_stats.gather_table_stats(user,'test1');

PL/SQL 过程已成功完成。

SQL> exec dbms_stats.gather_table_stats(user,'test2');

PL/SQL 过程已成功完成。

--再次执行该语句并查看其收集的信息

SQL> SELECT count(*)

  2    from test1 t1, test2 t2

  3   where t1.object_id = t2.object_id;

  COUNT(*)

----------

       100

SQL> SELECT * FROM table(dbms_xplan.display_cursor(NULL,NULL,'allstats last'));

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------------------

SQL_ID  dt23w69fu80v4, child number 0

------------------------------------------------------------------------------------------

SELECT count(*)   from test1 t1, test2 t2  where t1.object_id =

t2.object_id

Plan hash value: 2544416891

------------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |          |        1 |             |          1 |00:00:00.01 |      20 |           |           |          |
|   1 |  SORT AGGREGATE     |          |        1 |           1 |         1 |00:00:00.01 |      20 |            |           |          |
|*  2 |   HASH JOIN               |          |        1 |       100 |      100 |00:00:00.01 |      20 |  1517K|  1517K| 1463K (0)|
|   3 |    TABLE ACCESS FULL| TEST1 |       1 |       100 |      100 |00:00:00.01 |       4 |            |            |          |
|   4 |    TABLE ACCESS FULL| TEST2 |       1 |     1000 |     1000 |00:00:00.01 |      16 |           |            |          |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

已选择22行。

 表统计信息准确后,发现评估的行数与实际的行数完全一致。

附:查询出的统计信息标题含义

Starts:该sql执行的次数。

E-Rows:执行计划预计的行数。

A-Rows:实际返回的行数。

A-Time:每一步实际执行的时间(HH:MM:SS.FF),根据这一行可以知道该sql耗时在哪个地方。

Buffers:每一步实际执行的逻辑读或一致性读。

Reads:物理读。

OMem、1Mem:执行所需的内存评估值,OMem为最优执行模式所需内存的评估值,1Mem为one-pass模式所需内存的评估值。

O/1/M :最优/one-pass/multipass执行的次数。

Used-Mem:耗的内存。

注:如果执行中都没有涉及到的项,则在收集中就不会出现该项,如上述第一次执行的sql在收集的信息中有reads,但是表收集统计信息后再次执行因为不存在物理读,所以在第二个收集的信息中就没有reads这一项。