• 十分钟释疑Oracle中“小表超慢”之谜(SQL调优/SQL优化)


    前几天,一个用户找到我,说查一个小表的时候非常慢,我问有多慢,他说最快也得半个小时才能出结果,有时干脆不出结果,我说小表多大,他说就几十兆,有点疑惑,让他帮忙获取了相关信息,一看就明白了,原来所谓的小表是“假”的,下面是分析时参照的信息及分析的步骤。

    SQL语句:
    select * from t_rec where rec_date>trunc(sysdate-1);

    SQL计划:
    ------------------------------------------------------------------------------------------------------------
    | Id  | Operation                | Name            | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    ------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT         |                 |  2011 |   318K|   892   (3)| 00:00:13 |       |    |
    |   1 |  PARTITION RANGE ITERATOR|                 |  2011 |   318K|   892   (3)| 00:00:13 |   KEY |  21 |
    |*  2 |   TABLE ACCESS FULL      | T_REC |  2011 |   318K|   892   (3)| 00:00:13 |   KEY | 21 |
    ------------------------------------------------------------------------------------------------------------

    表所占空间:
    select sum(bytes)/1024/1024 "(MB)" from dba_extents where segment_name='T_REC';
          (MB)
    ----------
        38.675

    看到这里,我有点疑惑,表确实不大,但有个线索,大家注意到没有,那就是partition,如此小的表,有必要分区吗?莫非。。。

    desc t_rec

     名称                                      是否为空? 类型
     ----------------------------------------- -------- ----------------------------
     REC_ID                                    NOT NULL VARCHAR2(20)
     REC_NAME                                           VARCHAR2(200)
     REC_DESC                                           CLOB
     REC_DATE                                  NOT NULL DATE
     REC_CLASS                                          NUMBER
     REC_LEN                                            NUMBER

    至此,真相大白了,大家明白了吧?也许有的同学还是不明白,继续。。。

    select sum(bytes)/1024/1024/1024 "(GB)" from dba_extents 
    where partition_name in(
    select lob_partition_name from user_lob_partitions
    where table_name='T_REC');
          (GB)
    ----------
    309.31425

    明白了吗?呵呵,现在通过上面的信息,我们找到了”小表超慢“的原因,但这时,用户再次提出:我们怎么解决这个查询慢的问题呢?继续。。。

    select index_name,table_name,column_name from user_ind_columns where table_name='T_REC'

    INDEX_NAME                     TABLE_NAME                     COLUMN_NAME
    ------------------------------ ------------------------------ ----------------------------------------
    IDX1_REC_DATE                   T_REC                          REC_DATE
    IDX2_REC_ID                     T_REC                          REC_ID

    因为该库为用户生产库,且该表较大,所以,决定先通过hint测试效率问题:
    select /*+ index(t IDX1_REC_DATE)*/ * from t_rec t where rec_date>trunc(sysdate-1);

    加hint后计划:
    ---------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name                 | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
    ---------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                   |                      |  2011 |   318K|   912   (1)| 00:00:15 |       |       |
    |   1 |  PARTITION RANGE ITERATOR          |                      |  2011 |   318K|   912   (1)| 00:00:15 |   KEY |     21 |
    |   2 |   TABLE ACCESS BY LOCAL INDEX ROWID| T_REC      |  2011 |   318K|   912   (1)| 00:00:15 |   KEY |     21 |
    |*  3 |    INDEX RANGE SCAN                | IDX1_REC_DATE|  2011 |       |    14   (0)| 00:00:01 |   KEY |     21 |


    hint生效,测试2秒出结果,征求用户意见,用户说这样可以,至此问题解决,大家可以参照学习,禁止转载。

  • 相关阅读:
    面试题38:股票最大收益问题
    面试题37:字符串中的括号
    面试题36:罗马数和阿拉伯数的相互转换
    面试题35:大数(字符串)相乘
    面试题34:文本对齐
    面试题33:简化目录路径
    面试题32:字符串的通配符匹配
    并发调度的可串行性
    mysql limit查询(分页查询)探究
    通过宏定义将__declspec(dllexport)与__declspec(dllimport)的转化,实现库代码和使用代码使用同一份头文件
  • 原文地址:https://www.cnblogs.com/lhdz_bj/p/8681492.html
Copyright © 2020-2023  润新知