Oracle SQL:使用非唯一索引返回的子集中的行是否也可以使用第二个非唯一索引进行查询?

时间:2011-06-20 01:20:12

标签: sql oracle indexing

对不起,如果标题令人困惑,我发现很难清楚地说出我的问题。

这是我的情景: 我有一个名为SUBSCRIBERS的表,它有两个非唯一索引。索引的列是AREA_ID和SUBSCRIPTION_DATE。

现在,我想(有效地)查询在给定日期之后订阅的特定区域中的所有订阅者。示例SQL:

SELECT *
FROM subscribers
WHERE area_id = 'areaID'
AND subscription_date > to_date(some_date)

因此,假设执行此查询,Oracle首先获取具有给定areaID的所有行,并且假设这仍然是非常多的行。 Oracle是否能够按订阅日期对此子行进行范围扫描?或者非唯一的subscription_date索引是否仅适用于FULL表,这意味着Oracle必须对子集进行线性扫描?

另外,我不确定技术短语是什么意思来描述也适用于子集的集合上的索引。如果有人知道正确的术语,那将是一个很好的奖励。

2 个答案:

答案 0 :(得分:4)

根据Oracle版本的不同,可能会使用这两个索引。但是,为了做到这一点,Oracle必须将两个b树索引转换为位图索引,并在两者上进行位图合并。这不是一个特别有效的操作,因此通常不是您想要的查询计划。

Oracle b-tree索引通过将密钥和ROWID存储在发生密钥的表中来工作。为了组合索引,Oracle首先将它们转换为位图索引,该索引本质上是一个二维数组,指示哪一行符合哪个条件。然后它可以相对容易地组合两个位图索引。此操作的复杂性在于将b树索引初始转换为位图索引。原则上,没有什么能阻止Oracle实现一个查询计划,该计划从两个索引中获取所有ROWID并执行两个集合的交集。但是,我假设位图转换路径通常更有效,因为这是Oracle实现的。

Jonathan Lewis在他的“基于成本的Oracle基础知识”一书中有一节bitmap conversions

在(AREA_IDSUBSCRIPTION_DATE)上建立综合索引几乎肯定会更有效率。这将允许您对单个复合索引执行索引范围扫描。只有AREA_ID谓词的查询才能使用此复合索引,因此AREA_ID上的索引通常会变得多余。

答案 1 :(得分:1)

为了完整起见,我想发布Markus Winand网站上的这段摘录,直观地解释了为什么查询引擎无法同时使用多个不同的b-tree索引:

  

......一个带有一个轴的链条   支持一个范围条件作为访问谓词。支持两个   作为访问谓词的范围条件意味着扫描一个角落   棋盘。但是,B-Tree索引是一个链 - 没有第二个   轴。

来源:http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/index-merge-performance

有用的图表:http://use-the-index-luke.com/sql/anatomy/the-tree

换句话说,b树索引仅基于一个数据字段构造排序树。索引的节点是n元组,但索引的条目是1元组。

似乎查询一个b-tree索引返回的子集和第二个b-tree索引,第一个b-tree索引的条目需要另外存储对第二个b-中每一行位置的引用。树索引。但是,我不确定这是否会起作用,因为b-tree索引是基于而不是在位置上检索的 - 它们不是random access数据结构。

乍一看不确定会引入什么样的复杂性,但我确信它会成为多个索引的噩梦。您需要一种机制来添加其他索引位置引用(每个附加索引会将索引中的条目从n元组转换为(n + 1) - 元组),您需要一种机制来对其他索引应用过滤器跳过未引用的位置,您需要一种机制来在表上创建/更新/删除操作时跨索引同步引用。