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 - 未使用大表上的索引的主要内容,如果未能解决你的问题,请参考以下文章