• Statistics gathering and SQL Tuning Advisor


    1. https://www.pythian.com/blog/statistics-gathering-and-sql-tuning-advisor/

    Our monitoring software found a long running job on one of our client’s databases. The job was an Oracle’s auto task running statistics gathering for more than 3 hours. I was curious to know why it took so long and used a query to ASH to find out the most common SQL during the job run based on the module name. Results were surprising to me: top SQL was coming with SQL Tuning Advisor comment.

    Here is the SQL I used:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    SQL> select s.sql_id, t.sql_text, s.cnt
      from
      3    (select *
      4     from
      5      (
      6        select sql_id, count(*) cnt
      7        from v$active_session_history
      8        where action like 'ORA$AT_OS_OPT_SY%'
      9        group by sql_id
     10        order by count(*) desc
     11      )
     12     where rownum <= 5
     13    ) s,
     14    dba_hist_sqltext t
     15  where s.sql_id = t.sql_id;
     
    SQL_ID        SQL_TEXT                                                                                CNT
    ------------- -------------------------------------------------------------------------------- ----------
    020t65s3ah2pq select substrb(dump(val,16,0,32),1,120) ep, cnt from (select /*+ no_expand_table        781
    byug0cc5vn416 /* SQL Analyze(1) */ select /*+  full(t)    no_parallel(t) no_parallel_index(t)          43
    bkvvr4azs1n6z /* SQL Analyze(1) */ select /*+  full(t)    no_parallel(t) no_parallel_index(t)          21
    46sy4dfg3xbfn /* SQL Analyze(1) */ select /*+  full(t)    no_parallel(t) no_parallel_index(t)        1559

    So most queries are coming with “SQL Analyze” comment right in the beginning of SQL which is running from DBMS_STATS call, which is confusing. After some bug search I have found a MOS Doc ID 1480132.1 which includes a PL/SQL stack trace from a DBMS_STATS procedure call, and it is going up to DBMS_SQLTUNE_INTERNAL, which means DBMS_STATS has a call to the SQL Tuning package; very odd:

    1
    2
    3
    4
    5
    6
    7
    8
    SQL> select * from dba_dependencies where name = 'DBMS_STATS_INTERNAL' and referenced_name = 'DBMS_SQLTUNE_INTERNAL';
     
    OWNER                          NAME                           TYPE               REFERENCED_OWNER       REFERENCED_NAME
    ------------------------------ ------------------------------ ------------------ ------------------------------ ----------------------------------
    REFERENCED_TYPE    REFERENCED_LINK_NAME                                                                                                     DEPE
    ------------------ -------------------------------------------------------------------------------------------------------------------------------
    SYS                            DBMS_STATS_INTERNAL            PACKAGE BODY       SYS                    DBMS_SQLTUNE_INTERNAL
    PACKAGE                                                                                                                                     HARD

    Turns out, this call has nothing to do with the SQL Tuning. It is just a call to a procedure in this package, which happen to look like an SQL from SQL Tuning Advisor. I have traced a GATHER_TABLE_STATS call in a test database first with SQL trace and then with DBMS_HPROF and here is how the call tree looks like:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    SELECT RPAD(' ', (level-1)*2, ' ') || fi.owner || '.' || fi.module AS name,
           fi.function,
           pci.subtree_elapsed_time,
           pci.function_elapsed_time,
           pci.calls
    FROM   dbmshp_parent_child_info pci
           JOIN dbmshp_function_info fi ON pci.runid = fi.runid AND pci.childsymid = fi.symbolid
    WHERE  pci.runid = 1
    CONNECT BY PRIOR childsymid = parentsymid
      START WITH pci.parentsymid = 27;
    NAME                                     FUNCTION                       SUBTREE_ELAPSED_TIME FUNCTION_ELAPSED_TIME                CALLS
    ---------------------------------------- ------------------------------ -------------------- --------------------- --------------------
    ...
    SYS.DBMS_STATS_INTERNAL                  GATHER_SQL_STATS                           21131962                 13023                    1
      SYS.DBMS_ADVISOR                       __pkg_init                                       88                    88                    1
      SYS.DBMS_SQLTUNE_INTERNAL              GATHER_SQL_STATS                           21118776                  9440                    1
        SYS.DBMS_SQLTUNE_INTERNAL            I_PROCESS_SQL                              21107094              21104225                    1
          SYS.DBMS_LOB                       GETLENGTH                                        37                    37                    1
          SYS.DBMS_LOB                       INSTR                                            42                    42                    1
          SYS.DBMS_LOB                       __pkg_init                                       15                    15                    1
          SYS.DBMS_SQLTUNE_INTERNAL          I_VALIDATE_PROCESS_ACTION                        74                    39                    1
            SYS.DBMS_UTILITY                 COMMA_TO_TABLE                                   35                    35                    1
          SYS.DBMS_SQLTUNE_UTIL0             SQLTEXT_TO_SIGNATURE                            532                   532                    1
          SYS.DBMS_SQLTUNE_UTIL0             SQLTEXT_TO_SQLID                                351                   351                    1
          SYS.XMLTYPE                        XMLTYPE                                        1818                  1818                    1
        SYS.DBMS_SQLTUNE_UTIL0               SQLTEXT_TO_SQLID                                528                   528                    1
        SYS.DBMS_UTILITY                     COMMA_TO_TABLE                                   88                    88                    1
        SYS.DBMS_UTILITY                     __pkg_init                                       10                    10                    1
        SYS.SQLSET_ROW                       SQLSET_ROW                                       33                    33                    1
        SYS.XMLTYPE                          XMLTYPE                                        1583                  1583                    1
      SYS.DBMS_STATS_INTERNAL                DUMP_PQ_SESSTAT                                  73                    73                    1
      SYS.DBMS_STATS_INTERNAL                DUMP_QUERY                                        2                     2                    1
    ...

    So there is a procedure DBMS_SQLTUNE_INTERNAL.GATHER_SQL_STATS which is being called by DBMS_STATS_INTERNAL, and this procedure actually runs a SQL like this:

    1
    /* SQL Analyze(0) */ select /*+  full(t)    no_parallel(t) no_parallel_index(t) dbms_stats cursor_sharing_exact use_weak_name_resl dynamic_sampling(0) no_monitoring no_substrb_pad  */to_char(count("ID")),to_char(substrb(dump(min("ID"),16,0,32),1,120)),to_char(substrb(dump(max("ID"),16,0,32),1,120)),to_char(count("X")),to_char(substrb(dump(min("X"),16,0,32),1,120)),to_char(substrb(dump(max("X"),16,0,32),1,120)),to_char(count("Y")),to_char(substrb(dump(min("Y"),16,0,32),1,120)),to_char(substrb(dump(max("Y"),16,0,32),1,120)),to_char(count("PAD")),to_char(substrb(dump(min("PAD"),16,0,32),1,120)),to_char(substrb(dump(max("PAD"),16,0,32),1,120)) from "TIM"."T1" /* NDV,NIL,NIL,NDV,NIL,NIL,NDV,NIL,NIL,NDV,NIL,NIL*/

    Which is basically approximate NDV calculation. So, nothing to be afraid of, it’s just the way the code is organized: DBMS_STATS uses API of SQL Tuning framework when you are using DBMS_STATS.AUTO_SAMPLE_SIZE as the ESTIMATE_PERCENT (which is the default & recommended value in 11g+).

    附录1: 

    (approximate NDV calculation :  Column statistics data is an important factor for CBO to estimate cost of execution plan. There are generally two kinds of statistics data on columns, one is the synopses, such as NDV, ACL and maximum/minimum data; the other is histogram. A single scanning table can get those synopses. To analyze the large tables with low cost, we normally sampling the data.)

     附录2:

    解释:are using DBMS_STATS.AUTO_SAMPLE_SIZE as the ESTIMATE_PERCENT (which is the default & recommended value in 11g+).
    1. If, during processing, the procedure determines that the returned information for the sample is insufficient for accurate access path selection, the sample can be increased by a factor of ten and restarted. For example, if AUTO_SAMPLE_SIZE started with around 5500 rows, when the procedure determines that the sample is insufficient, then it will then increase the sample (for example to 55000) and restart. If this is insufficient, it increases by another factor of 10, and so on. However, if the sample size exceeds 25% of the table size, it will switch automatically to COMPUTE (100% sample).

    2. There is a case where the sample taken is sufficient for accurate statistics, but the number of rows is judged to be poorly estimated (either for the table or an index). Sample_size is set at the lower value, but then dbms_stats will take an accurate row count by using SELECT COUNT(*) from the table and index. As well as setting the num_rows, dbms_stats will also set the sample_size to this value (as this is the number of rows sampled to produce num_rows). In this case, the sample_size, although accurate for the last operation, is misleading as far as the full sample taken for the other gathered statistics.

    2.

    http://blog.csdn.net/stevendbaguo/article/details/50856002

     接到现场数据库维护厂商发出的警告,有一条 insert语句执行了几千秒。

           开发排查,从select * from dba_source s where s.text like '%XXX%';查到是一个存储过程,于是找到存储过程,将其改名。

           但问题没有解决,隔天又收到警告。

           难道是存储过程改名有问题,我远程到现场看了下,并没有问题。再次查看数据库报告:

           SQL Module  是 DBMS_SCHEDULER,确定无疑是Oracle JOB调用,奇怪的是SQL语句有  /* SQL Analyze(194, 1) */ 这样的提示。

           如果想定位到这条SQL,最好是找到这条SQL历史执行的session,希望找到蛛丝马迹。

           select * from dba_hist_active_sess_history s where s.sql_id='29yrhxqdk2d1q'; 

           TOP_LEVEL_SQL_ID 为5zruc4v6y32f9:说明是sql_id为5zruc4v6y32f9的调用的这条sql 

           MODULE:DBMS_SCHEDULER

           PLSQL_ENTRY_OBJECT_ID:9013

           根据上面的信息再进行查询:

    9013;--结果是owner=sys  object_name=dbms_sqltune

    5zruc4v6y32f9

    DECLARE
      job                 BINARY_INTEGER := :job;
      next_date           TIMESTAMP WITH TIME ZONE := :mydate;
      broken              BOOLEAN := FALSE;
      job_name            VARCHAR2(30) := :job_name;
      job_subname         VARCHAR2(30) := :job_subname;
      job_owner           VARCHAR2(30) := :job_owner;
      job_start           TIMESTAMP WITH TIME ZONE := :job_start;
      job_scheduled_start TIMESTAMP WITH TIME ZONE := :job_scheduled_start;
      window_start        TIMESTAMP WITH TIME ZONE := :window_start;
      window_end          TIMESTAMP WITH TIME ZONE := :window_end;
      chain_id            VARCHAR2(14) := :chainid;
      credential_owner    varchar2(30) := :credown;
      credential_name     varchar2(30) := :crednam;
      destination_owner   varchar2(30) := :destown;
      destination_name    varchar2(30) := :destnam;
      job_dest_id         varchar2(14) := :jdestid;
      log_id              number := :log_id;
    BEGIN
      DECLARE
        ename VARCHAR2(30);
      BEGIN
        ename := dbms_sqltune.execute_tuning_task('SYS_AUTO_SQL_TUNING_TASK');
      END;
      :mydate := next_date;
      IF broken THEN
        :b := 1;
      ELSE
        :b := 0;
      END IF;
    END;

           这是数据库SQL优化的包,自己调用的,终于明白 /* SQL Analyze(194, 1) */的意思了,是标记这种优化包调用的。

    3.

    http://blog.itpub.net/23718752/viewspace-1252180/

    在昨天晚上10点开始,数据库的性能开始下降,出现了一些j00开头的进程。
    而且持续了比较长的时间,简单分析了一下,对应的进程执行的sql语句如下。

    ####### Process Information from OS level as below ########
    oraccbs1 16184     1 23 22:00 ?        00:03:09 ora_j000_PETCUS1
    oraccbs1 20829 12754  0 22:14 pts/12   00:00:00 ksh showpid.sh 16184
    ##############################################

           SID    SERIAL# USERNAME        OSUSER          MACHINE              PROCESS         TERMINAL        TYPE       LOGIN_TIME
    ---------- ---------- --------------- --------------- -------------------- --------------- --------------- ---------- -------------------
          1139       1071 SYS             oraccbs1        xxxxxx               16184           UNKNOWN         USER       2014-08-14 22:00:43

    .

    SQL_ID                         SQL_TEXT
    ------------------------------ ------------------------------------------------------------
    6fwshkjydz9ph                  /* SQL Analyze(1) */ select /*+  full(t)    no_parallel(t) n
                                   o_parallel_index(t) dbms_stats cursor_sharing_exact use_weak
                                   _name_resl dynamic_sampling(0) no_monitoring no_substrb_pad
                                    */to_char(count("PERIOD_KEY")),to_char(substrb(dump(min("PE
                                   RIOD_KEY"),16,0,32),1,120)),to_char(substrb(dump(max("PERIOD
                                   _KEY"),16,0,32),1,120)),to_char(count("PARTITION_ID")),to_ch
                                   ar(substrb(dump(min("PARTITION_ID"),16,0,32),1,120)),to_char
                                   (substrb(dump(max("PARTITION_ID"),16,0,32),1,120)),to_char(c
                                   ount("DEBIT_ID")),to_char(substrb(dump(min("DEBIT_ID"),16,0,
                                   32),1,120)),to_char(substrb(dump(max("DEBIT_ID"),16,0,32),1,
                                   120)),to_char(count("SYS_CREATION_DATE")),to_char(substrb(du
                                   mp(min("SYS_CREATION_DATE"),16,0,32),1,120)),to_char(substrb
                                   (dump(max("SYS_CREATION_DATE"),16,0,32),1,120)),to_char(coun
                                   t("SYS_UPDATE_DATE")),to_char(substrb(dump(min("SYS_UPDATE_D
                                   ATE"),16,0,32),1,120)),to_char(substrb(dump(max("SYS_UPDATE_
                                   DATE"),16,0,32),1,120)),to_char(count("OPERATOR_ID")),to_cha
                                   r(substrb(dump(min("OPERATOR_ID"),16,0,3

     

    PREV_SQL_ID                    SQL_TEXT
    ------------------------------ ------------------------------------------------------------
    fhzj09a7fnrnb                  SELECT DBTIMEZONE, LENGTH(DBTIMEZONE) FROM SYS.DUAL

     
    看起来是在做一些后台的维护工作。在11g中引入了几个schedule job,简单查询,结果如下。可以看到在每天都设置了对应的window。
    在10点开始做一些工作。以下是禁用以后的状态。

    SQL> execute DBMS_AUTO_TASK_ADMIN.DISABLE;

    PL/SQL procedure successfully completed.

    SQL> select * from DBA_AUTOTASK_WINDOW_CLIENTS;

    WINDOW_NAME                    WINDOW_NEXT_TIME                                                            WINDO AUTOTASK OPTIMIZE SEGMENT_ SQL_TUNE HEALTH_M
    ------------------------------ --------------------------------------------------------------------------- ----- -------- -------- -------- -------- --------
    MONDAY_WINDOW                  18-AUG-14 10.00.00.000000 PM ASIA/PHNOM_PENH                                FALSE DISABLED ENABLED  ENABLED  ENABLED  DISABLED
    TUESDAY_WINDOW                 19-AUG-14 10.00.00.000000 PM ASIA/PHNOM_PENH                                FALSE DISABLED ENABLED  ENABLED  ENABLED  DISABLED
    WEDNESDAY_WINDOW               20-AUG-14 10.00.00.000000 PM ASIA/PHNOM_PENH                                FALSE DISABLED ENABLED  ENABLED  ENABLED  DISABLED
    THURSDAY_WINDOW                14-AUG-14 10.00.00.000000 PM ASIA/PHNOM_PENH                                TRUE  DISABLED ENABLED  ENABLED  ENABLED  DISABLED
    FRIDAY_WINDOW                  15-AUG-14 10.00.00.000000 PM ASIA/PHNOM_PENH                                FALSE DISABLED ENABLED  ENABLED  ENABLED  DISABLED
    SATURDAY_WINDOW                16-AUG-14 06.00.00.000000 AM ASIA/PHNOM_PENH                                FALSE DISABLED ENABLED  ENABLED  ENABLED  DISABLED
    SUNDAY_WINDOW                  17-AUG-14 06.00.00.000000 AM ASIA/PHNOM_PENH                                FALSE DISABLED ENABLED  ENABLED  ENABLED  DISABLED

    7 rows selected.

    其实3个主要的后台job可以选择关掉。

    SQL> select client_name,status from DBA_AUTOTASK_CLIENT;


    CLIENT_NAME                                                      STATUS
    ---------------------------------------------------------------- --------
    auto optimizer stats collection                                  ENABLED
    auto space advisor                                               ENABLED
    sql tuning advisor                                               ENABLED

    使用如下的pl/sql来禁用。

    begin
    DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'auto optimizer stats collection',
    operation => NULL,
    window_name => NULL);
    end;
    /


    begin
    DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'auto space advisor',
    operation => NULL,
    window_name => NULL);
    end;
    /

    begin
    DBMS_AUTO_TASK_ADMIN.DISABLE(client_name => 'sql tuning advisor',
    operation => NULL,
    window_name => NULL);
    end;
    /

    禁用以后,状态如下:

    SQL> select client_name,status from DBA_AUTOTASK_CLIENT;

    CLIENT_NAME                                                      STATUS
    ---------------------------------------------------------------- --------
    auto optimizer stats collection                                  DISABLED
    auto space advisor                                               DISABLED
    sql tuning advisor                                               DISABLED

    但是不会当时生效,需要过一段时间,所以需要提前禁用。

  • 相关阅读:
    数据库访问优化之四:减少数据库服务器CPU运算
    数据库访问优化之三:减少交互次数
    数据库访问优化之二:返回更少的数据
    数据库访问优化之一:减少数据访问
    数据库性能优化
    磁盘映射
    strcmp
    程序设计基础
    Linux——【rpm、yun、源码包】安装
    Rsa2加密报错java.security.spec.InvalidKeySpecException的解决办法
  • 原文地址:https://www.cnblogs.com/feiyun8616/p/6549642.html
Copyright © 2020-2023  润新知