文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Oracle函数使索引列失效怎么办

2023-06-22 03:19

关注

小编给大家分享一下Oracle函数使索引列失效怎么办,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

一、数据版本与原始语句及相关信息

版本信息

SQL> select * from v$version;                                                                                                           BANNER                                                              ----------------------------------------------------------------    Oracle Database 10g Release 10.2.0.3.0 - 64bit Production           PL/SQL Release 10.2.0.3.0 - Production                              CORE    10.2.0.3.0      Production                                  TNS for Linux: Version 10.2.0.3.0 - Production                      NLSRTL Version 10.2.0.3.0 - Production

 2.原始语句与其执行计划

SQL> set autotrace traceonly exp;                                                                                                                                                                   SELECT acc_num,                                                                                      curr_cd,                                                                                        DECODE('20110728',                                                                             (SELECT TO_CHAR(LAST_DAY(TO_DATE('20110728', 'YYYYMMDD')),                                  'YYYYMMDD')                                                                          FROM   DUAL),                                                                              0,                                                                                          adj_credit_int_lv1_amt + adj_credit_int_lv2_amt -                                           adj_debit_int_lv1_amt - adj_debit_int_lv2_amt) AS interest                                FROM   acc_pos_int_tbl ACC_POS_INT_TBL1                                                           WHERE  SUBSTR(business_date, 1, 6) = SUBSTR('20110728', 1, 6)                                        AND business_date <= '20110728';                                                                                                                                                               Execution Plan                                                                                    ----------------------------------------------------------                                        Plan hash value: 3114115399                                                                                                                                                                         -------------------------------------------------------------------------------------             | Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |             -------------------------------------------------------------------------------------             |   0 | SELECT STATEMENT  |                 |   336K|    12M| 96399   (1)| 00:19:17 |             |   1 |  FAST DUAL        |                 |     1 |       |     2   (0)| 00:00:01 |             |*  2 |  TABLE ACCESS FULL| ACC_POS_INT_TBL |   336K|    12M| 96399   (1)| 00:19:17 |             -------------------------------------------------------------------------------------                                                                                                               Predicate Information (identified by operation id):                                               ---------------------------------------------------                                                                                                                                                    2 - filter(SUBSTR("BUSINESS_DATE",1,6)='201107' AND                                                          "BUSINESS_DATE"<='20110728')

表上的索引信息

SQL> set autotrace off;                                                                                  SQL> set linesize 190                                                                                    SQL> @Idx_Info                                                                                           Enter value for owner: goex_admin                                                                        old  10:           AND owner = upper('&owner')                                                           new  10:           AND owner = upper('goex_admin')                                                       Enter value for table_name: ACC_POS_INT_TBL                                                              old  11:           AND a.table_name = upper('&table_name')                                               new  11:           AND a.table_name = upper('ACC_POS_INT_TBL')                                                                                                                                                    TABLE_NAME         INDEX_NAME               COL_NAM              CL_POS STATUS   IDX_TYP         DSCD    ------------------ ------------------------ -------------------- ------ -------- --------------- ----    ACC_POS_INT_TBL    ACC_POS_INT_10DIG_IDX    SYS_NC00032$              1 VALID    FUNCTION-BASED  ASC                                                                                      NORMAL                                                                                                                           ACC_POS_INT_TBL    ACC_POS_INT_10DIG_IDX    BUSINESS_DATE             2 VALID    FUNCTION-BASED  ASC                                                                                      NORMAL                                                                                                                           ACC_POS_INT_TBL    ACC_POS_INT_10DIG_IDX    CURR_CD                   3 VALID    FUNCTION-BASED  ASC                                                                                      NORMAL                                                                                                                           ACC_POS_INT_TBL    PK_ACC_POS_INT_TBL       ACC_NUM                   1 VALID    NORMAL          ASC     ACC_POS_INT_TBL    PK_ACC_POS_INT_TBL       BUSINESS_DATE             2 VALID    NORMAL          ASC

从索引的情况上来看有一个基于主键的索引包含了BUSINESS_DATE列,而查询语句并没有走索引而是选择的全表扫描,而且预估所返回的行Rows与bytes也是大的惊人,cost的值96399,接近10W。

二、分析与改造SQL语句

原始的SQL语句分析

SQL语句中where子句的business_date列实现对记录过滤business_date <= '20110728'条件不会限制索引的使用SUBSTR(business_date, 1, 6) = SUBSTR('20110728', 1, 6)使用了SUBSTR函数,限制了优化器选择索引基于business_date列来建立索引函数,从已存在的索引来看,必要性不大

改造SQL语句

SUBSTR(business_date, 1, 6) = SUBSTR('20110728', 1, 6)的实质是等于当月,即限制返回的行为从2011.7.1日至2011.7.28因此其返回的记录大于等于2011.7.1,且小于2011.7.28做如下改造business_date >=to_char(last_day(add_months(to_date('20110728','yyyymmdd'),-1)) + 1,'yyyymmdd')

改造后的SQL语句

SELECT acc_num,                                                                   curr_cd,                                                                     DECODE('20110728',                                                          (SELECT TO_CHAR(LAST_DAY(TO_DATE('20110728', 'YYYYMMDD')),               'YYYYMMDD')                                                       FROM   DUAL),                                                           0,                                                                       adj_credit_int_lv1_amt + adj_credit_int_lv2_amt -                        adj_debit_int_lv1_amt - adj_debit_int_lv2_amt) AS interest             FROM   acc_pos_int_tbl ACC_POS_INT_TBL1                                        WHERE  business_date >=                                                           to_char(last_day(add_months(to_date('20110728', 'yyyymmdd'), -1)) + 1,       'yyyymmdd')                                                              AND business_date <= '20110728';

改造后的执行计划

Execution Plan                                                                                               ----------------------------------------------------------                                                   Plan hash value: 66267922                                                                                                                                                                                                 --------------------------------------------------------------------------------------------------           | Id  | Operation                   | Name               | Rows  | Bytes | Cost (%CPU)| Time     |           --------------------------------------------------------------------------------------------------           |   0 | SELECT STATEMENT            |                    |  1065K|    39M| 75043   (1)| 00:15:01 |           |   1 |  FAST DUAL                  |                    |     1 |       |     2   (0)| 00:00:01 |           |   2 |  TABLE ACCESS BY INDEX ROWID| ACC_POS_INT_TBL    |  1065K|    39M| 75043   (1)| 00:15:01 |           |*  3 |   INDEX SKIP SCAN           | PK_ACC_POS_INT_TBL | 33730 |       | 41180   (1)| 00:08:15 |           --------------------------------------------------------------------------------------------------                                                                                                                        Predicate Information (identified by operation id):                                                          ---------------------------------------------------                                                                                                                                                                          3 - access("BUSINESS_DATE">='20110701' AND "BUSINESS_DATE"<='20110728')                                          filter("BUSINESS_DATE">='20110701' AND "BUSINESS_DATE"<='20110728')

改造后可以看到SQL语句的执行计划已经由原来的全表扫描改为执行INDEX SKIP SCAN,但其cost也并没有降低多少

三、进一步分析

表的相关信息

SQL> @Tab_Stat                                                                                        Enter value for input_table_name: ACC_POS_INT_TBL                                                     old  11: WHERE  table_name = upper('&input_table_name')                                               new  11: WHERE  table_name = upper('ACC_POS_INT_TBL')                                                 Enter value for input_owner: goex_admin                                                               old  12:           AND owner = upper('&input_owner')                                                  new  12:           AND owner = upper('goex_admin')                                                                                                                                                            NUM_ROWS       BLKS    EM_BLKS  AVG_SPACE  CHAIN_CNT AVG_ROW_LEN AVG_ROWS_PER_BLOCK LST_ANLY  STA   ---------- ---------- ---------- ---------- ---------- ----------- ------------------ --------- ---     33659947     437206       1322        855          0          99                 77 27-SEP-11 NO

索引的相关信息

SQL> @Idx_Stat                                                                                                       Enter value for input_table_name: ACC_POS_INT_TBL                                                                    old  11: WHERE  table_name = upper('&input_table_name')                                                              new  11: WHERE  table_name = upper('ACC_POS_INT_TBL')                                                                Enter value for input_owner: goex_admin                                                                              old  12:           AND owner = upper('&input_owner')                                                                 new  12:           AND owner = upper('goex_admin')                                                                                                                                                                                        BLEV IDX_NAME                          LF_BLKS   DST_KEYS   NUM_ROWS LF_PER_KEY DAT_BLK_PER_KEY   CLUS_FCT LST_ANLY  ---- ------------------------------ ---------- ---------- ---------- ---------- --------------- ---------- ---------    3 PK_ACC_POS_INT_TBL                 155658   33777720   33777720          1               1   33777447 27-SEP-11    3 ACC_POS_INT_10DIG_IDX              160247   32850596   32850596          1               1   32763921 27-SEP-11

尝试在BUSINESS_DATE列上创建索引

SQL> create index I_ACC_POS_INT_TBL_BS_DT on ACC_POS_INT_TBL(BUSINESS_DATE) tablespace tbs_tmp nologging;                                                                                                                                   Index created.                                                                                                                                                                                                                              SQL> @Idx_Stat                                                                                                        Enter value for input_table_name: ACC_POS_INT_TBL                                                                     old  11: WHERE  table_name = upper('&input_table_name')                                                               new  11: WHERE  table_name = upper('ACC_POS_INT_TBL')                                                                 Enter value for input_owner: goex_admin                                                                               old  12:           AND owner = upper('&input_owner')                                                                  new  12:           AND owner = upper('goex_admin')                                                                                                                                                                                          BLEV IDX_NAME                          LF_BLKS   DST_KEYS   NUM_ROWS LF_PER_KEY DAT_BLK_PER_KEY   CLUS_FCT LST_ANLY   ---- ------------------------------ ---------- ---------- ---------- ---------- --------------- ---------- ---------     2 I_ACC_POS_INT_TBL_BS_DT             93761        908   33659855        103             506     460007 30-SEP-11     3 PK_ACC_POS_INT_TBL                 155658   33777720   33777720          1               1   33777447 27-SEP-11     3 ACC_POS_INT_10DIG_IDX              160247   32850596   32850596          1               1   32763921 27-SEP-11

建立索引后聚簇因子较小,差不多接近表上块的数量

使用新创建索引后的执行计划

Execution Plan                                                                                               ----------------------------------------------------------                                                   Plan hash value: 2183566226                                                                                                                                                                                               -------------------------------------------------------------------------------------------------------      | Id  | Operation                   | Name                    | Rows  | Bytes | Cost (%CPU)| Time     |      -------------------------------------------------------------------------------------------------------      |   0 | SELECT STATEMENT            |                         |  1065K|    39M| 17586   (1)| 00:03:32 |      |   1 |  FAST DUAL                  |                         |     1 |       |     2   (0)| 00:00:01 |      |   2 |  TABLE ACCESS BY INDEX ROWID| ACC_POS_INT_TBL         |  1065K|    39M| 17586   (1)| 00:03:32 |      |*  3 |   INDEX RANGE SCAN          | I_ACC_POS_INT_TBL_BS_DT |  1065K|       |  2984   (1)| 00:00:36 |      -------------------------------------------------------------------------------------------------------                                                                                                                   Predicate Information (identified by operation id):                                                          ---------------------------------------------------                                                                                                                                                                          3 - access("BUSINESS_DATE">='20110701' AND "BUSINESS_DATE"<='20110728')

从上面的执行计划看出,SQL语句已经选择了新建的索引尽管返回的rows,bytes没有明显的变化,但cost已经少了近7倍。

看完了这篇文章,相信你对“Oracle函数使索引列失效怎么办”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯