Oracle - 未使用大表上的索引

Posted

技术标签:

【中文标题】Oracle - 未使用大表上的索引【英文标题】:Oracle - Index on large table not used 【发布时间】:2015-05-27 01:34:38 【问题描述】:

我有两个表 MP_LM 和 MP_BS,这两个表如下连接到一个视图并在 select 语句中使用。

CREATE VIEW MV_MP_LM_V (MP_ID,ID,PID,NAME,IS_D) AS
SELECT C.mp_ID,C.BS_ID ID,NULL      PID,C.BS_NM NAME,'Y'       IS_D FROM MP_BS C UNION
SELECT CM.mp_ID,CM.LM_ID ID,CM.IT_ID PID,CM.LM_NM NAME,CM.IS_D FROM MP_LC_REF_ORIG CM WHERE FLG = 'Y' ;

表MP_BS的PK如下。

ALTER TABLE MP_BS ADD CONSTRAINT MP_BS_PK PRIMARY KEY (MP_ID, BS_ID, BS_NM);

下面是我正在运行的 Select。

SELECT DISTINCT
ID,
              PID,
              NAME,
              DECODE (pid,
                      NULL, DECODE (id, -1, NULL, id || '$'),
                      pid || '$' || id)
                 tree_id,
              DECODE (ID, -1, 0, 1) s1
         FROM  MV_MP_LM_V, TABLE (MV_SPLITARR5 (336700164 , ',', '$')) c
        WHERE     mp_ID = c.id1
              AND IS_D= 'Y'
              AND ID <> -1
              AND (   0 = 0
                   OR (    0 > 0

                            ))
     ORDER BY s1, DECODE (pid, NULL, 0, 1), name;

对于上面的选择,没有索引 MP_BS_PK ,选择需要 35 秒,下面是计划..

Plan hash value: 2313865915

-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name               | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                    |   206M|   123G|       |    56M  (1)|188:17:27 |
|   1 |  SORT ORDER BY                       |                    |   206M|   123G|   131G|    56M  (1)|188:17:27 |
|   2 |   HASH UNIQUE                        |                    |   206M|   123G|   131G|    28M  (1)| 94:49:48 |
|*  3 |    HASH JOIN                         |                    |   206M|   123G|       |   410K  (1)| 01:22:09 |
|   4 |     COLLECTION ITERATOR PICKLER FETCH| MV_SPLITARR5       |  8168 | 16336 |       |    29   (0)| 00:00:01 |
|   5 |     VIEW                             | MV_MP_LM_V         |  2529K|  1546M|       |   409K  (1)| 01:21:56 |
|   6 |      SORT UNIQUE                     |                    |  2529K|  1489M|  1572M|   409K  (1)| 01:21:56 |
|   7 |       UNION-ALL                      |                    |       |       |       |            |          |
|*  8 |        TABLE ACCESS FULL             | MP_BS              |   121K|  2964K|       |   377   (1)| 00:00:05 |
|*  9 |        TABLE ACCESS FULL             | MP_LM_REF_ORIG     |  2408K|  1486M|       | 79820   (1)| 00:15:58 |
-------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("MP_ID"=TO_NUMBER(SYS_OP_ATG(VALUE(KOKBF$),1,2,2)))
   8 - filter("C"."BS_ID"<>(-1))
   9 - filter("CM"."LM_ID"<>(-1) AND "FLG"='Y' AND "CM"."IS_D"='Y')

Note
-----
   - dynamic sampling used for this statement (level=2)

对于 pk,选择需要 10 秒,下面是这个计划。

Plan hash value: 2486203413

-----------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                    |       |  1929 | 26028   (1)| 00:05:13 |
|   1 |  SORT ORDER BY                       |                    |       |  1929 | 26028   (1)| 00:05:13 |
|   2 |   HASH UNIQUE                        |                    |       |  1929 | 26027   (1)| 00:05:13 |
|*  3 |    HASH JOIN                         |                    |     3 |  1929 | 26026   (1)| 00:05:13 |
|   4 |     VIEW                             | MV_MP_LM_V         |    10 |  6410 | 25997   (1)| 00:05:12 |
|   5 |      SORT UNIQUE                     |                    |       |       |            |          |
|   6 |       UNION-ALL                      |                    |       |       |            |          |
|*  7 |        INDEX FAST FULL SCAN          | MP_BS_PK           |   121K|  2964K|   192   (1)| 00:00:03 |
|*  8 |        TABLE ACCESS FULL             | MP_LM_REF_ORIG     |  2408K|  1486M| 79820   (1)| 00:15:58 |
|   9 |     COLLECTION ITERATOR PICKLER FETCH| MV_SPLITARR5       |  8168 | 16336 |    29   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("MP_ID"=TO_NUMBER(SYS_OP_ATG(VALUE(KOKBF$),1,2,2)))
   7 - filter("C"."BS_ID"<>(-1))
   8 - filter("CM"."LM_ID"<>(-1) AND "FLG"='Y' AND "CM"."IS_D"='Y')

Note
-----
   - dynamic sampling used for this statement (level=2)

我研究了很多东西,但找不到为什么较小表上的 pk/index 会提供更快的性能。

没有。每个表中的行数是:

MP_LM_REF_ORIG :- 10241670
MP_BS :- 147575

我尝试在 ID MP_ID 上的表 MP_LM_REF_ORIG 上创建索引,但未使用该索引。

谁能解释一下 MP_BS 上的这个索引如何帮助提高性能。

【问题讨论】:

这样做的目的是什么:AND (0 = 0 OR (0 > 0)) ??尝试添加使用索引的提示? 索引快速全扫描明显快于表全扫描,但似乎并不能解释第二次查询的速度。多少条记录产生此查询:SELECT CM.mp_ID,CM.LM_ID ID,CM.IT_ID PID,CM.LM_NM NAME,CM.IS_D FROM MP_LC_REF_ORIG CM WHERE FLG = 'Y' and IS_D='Y'; @OldProgrammer - AND ( 0 = 0 OR ( 0 > 0 ) ) 是用变量替换的查询框架。我在 MP_LC_REF_ORIG(MP_ID) 上有索引,但即使我给出索引提示,它也不起作用.. SELECT /*+ INDEX(MP_LM_REF_ORIG IDX_MP_LM_REF) */ ID, PID, ......... @FlorinGhita - 带有两个过滤器的表 MP_LC_REF_ORIG 有 2653814 条记录。 【参考方案1】:

至少有两个原因:

    INDEX FAST FULL SCAN 而不是 TABLE ACCESS FULL 即不是对表进行全扫描,而是对索引进行全扫描,这可能比对应的表更小 UNION 需要删除重复的行,在计划中,这由union all 后跟sort unique 表示。使用索引时,使用索引返回的数据已经排序,因此这可能是另一个性能提升。

【讨论】:

以上是关于Oracle - 未使用大表上的索引的主要内容,如果未能解决你的问题,请参考以下文章

未使用存储过程创建索引 - Oracle

ORACLE 大表索引问题:数据量5亿+,做查询,按时间一个月分区,查询会用到3 4个字段,如何见索引

日期字段上的 Postgres DESC 索引

如何监控ORACLE索引使用与否

Mysql join

Oracle 11g新特性invisible index(不可见的索引)