Oracle 压缩/b-tree 索引如何以及何时使用

Posted

技术标签:

【中文标题】Oracle 压缩/b-tree 索引如何以及何时使用【英文标题】:Oracle compressed/b-tree index how and when to use 【发布时间】:2018-01-29 12:43:40 【问题描述】:

我想向 Oracle 应用程序工作流表 hr.pqh_ss_transaction_history 添加压缩索引,以便访问特定类型的工作流 (process_name) 和特定人员的工作流 (selected_person_id)。

process_name 中有很多重复值,尽管数据有偏差。但是,我想访问 TFG_HR_NEW_HIRE_PLACE_JSP_PRCTFG_HR_TERMINATION_JSP_PRC 进程类型。

"PROCESS_NAME","CNT"
"HR_GENERIC_APPROVAL_PRC",40347
"HR_PERSONAL_INFO_JSP_PRC",39284
"TFG_HR_NEW_HIRE_PLACE_JSP_PRC",18117
"TFG_HREMPSTS_TERMS_CHG_JSP_PRC",14076
"TFG_HR_TERMINATION_JSP_PRC",8764
"HR_ADV_INDIVIDUAL_COMP_PRC",4907
"TFG_HR_SIT_NOAPP",3979
"TFG_YE_TAX_PROV",2663
"HR_TERMINATION_JSP_PRC",1310
"HR_CHANGE_PAY_JSP_PRC",953
"TFG_HR_SIT_EXIT_JSP_PRC",797
"HR_SIT_JSP_PRC",630
"HR_QUALIFICATION_JSP_PRC",282
"HR_CAED_JSP_PRC",250
"TFG_HR_EMP_TERM_JSP_PRC",211
"PER_DOR_JSP_PRC",174
"HR_AWARD_JSP_PRC",101
"TFG_HR_SIT_REP_MOT",32
"TFG_HR_SIT_NEWPOS_NIB_JSP_PRC",30
"TFG_HR_SIT_NEWPOS_INBU_JSP_PRC",28
"HR_NEW_HIRE_PLACE_JSP_PRC",22
"HR_NEWHIRE_JSP_PRC",6

selected_person_id 显然更具选择性。不幸的是,此列有 3774 个空值,之后的最高计数是一个人的 73 个。很多人只会有 1 行。总行数为 136963。

我的查询将采用以下格式:

select psth.item_key,
       psth.creation_date,
       psth.last_update_date
from   hr.pqh_ss_transaction_history psth
where  nvl(psth.selected_person_id, :p_person_id) = :p_person_id
and    psth.process_name = 'HR_TERMINATION_JSP_PRC'
order  by psth.last_update_date

我使用的是 Oracle 12c 第 1 版。

我认为在selected_person_id 上放置一个非压缩的 b 树索引是个好主意,因为返回的值将低于总行数的 5%,但是如何处理空值在使用nvl(psth.selected_person_id, :p_person_id) = :p_person_id 选择时不会进入索引的列中?有没有更高效的写sql的方法,应该如何创建这个索引?

对于process_name,我想使用压缩的 b 树索引。我假设声明是

CREATE INDEX idxname ON pqh_ss_transaction_history(process_name) COMPRESS 

rowid 会有一个隐含的第二列。在这里使用 rowid 是否安全,因为通常不建议使用 rowid?偏斜的数据是否是一个问题(大多数时候我会选择高容量侧)?我不明白压缩索引的效率如何。对于 b-tree 索引,您通常希望返回 5% 的数据,否则全表扫描实际上更有效。压缩索引如何返回这么多rowids,然后使用这些rowids 查找全表,比全表扫描更快?

或者由于优化器只能使用这两个索引之一,我应该创建一个基于未压缩函数的索引,并将selected_person_idprocess_name 连接起来?

【问题讨论】:

where psth.selected_person_id = nvl(:p_person_id, psth.selected_person_id) 永远不会显示psth.selected_person_id 为空的行。这是故意的吗? 糟糕。应该在哪里 nvl(psth.selected_person_id, :p_person_id) = :p_person_id 所以无论你要求什么 person_id,你都会得到那个加所有没有 person_id 的行? 是的,我想要空值和 :p_person_id 与值匹配的值。 【参考方案1】:

也许你可以创建这个索引:

CREATE INDEX idxname ON pqh_ss_transaction_history
  (process_name, NVL(selected_person_id,-1)) COMPRESS 1

然后将您的查询更改为:

select psth.item_key,
       psth.creation_date,
       psth.last_update_date
from   hr.pqh_ss_transaction_history psth
where  nvl(psth.selected_person_id, -1) in (:p_person_id,-1)
and    psth.process_name = 'HR_TERMINATION_JSP_PRC'
order  by psth.last_update_date

【讨论】:

:p_person_id 将永远是一些东西,只是 Oracle 出于某种原因并不总是存储 selected_person_id(即使它是所有工作流要求的第一件事)。 好的,您希望查询返回所有selected_person_id 为空的行以及匹配 :person_id 值的行吗? 是的,我想要空值和 :p_person_id 与值匹配的值。 根据新要求重写答案! 不应该是 CREATE INDEX idxname ON pqh_ss_transaction_history (process_name, NVL(selected_person_id,-1)) COMPRESS 1

以上是关于Oracle 压缩/b-tree 索引如何以及何时使用的主要内容,如果未能解决你的问题,请参考以下文章

Mysql和ORACLE索引的实现方式

MySQL索引

B-Tree vs Bitmap 数据库索引

各种Oracle索引类型介绍

各种Oracle索引类型介绍

Oracle索引总结- Oracle索引种类之位图索引