相同列上的 Oracle 2 索引但顺序不同

Posted

技术标签:

【中文标题】相同列上的 Oracle 2 索引但顺序不同【英文标题】:Oracle 2 Indexes on same columns but different order 【发布时间】:2013-08-25 16:23:08 【问题描述】:

我在生产环境中有一个表,该表上有 2 个索引,索引中的列相同,但顺序相反。

DDL 是

 - CREATE INDEX IND_1 ON ORDERS (STORE_ID,DIST_ID)  
 - CREATE INDEX IND_DL_1 ON ORDERS (DIST_ID,STORE_ID)

这两个索引本质上是否不相同。为什么有人会以这种方式创建索引?反转或更改列位置是否在内部执行某些操作?

【问题讨论】:

索引中列顺序的经验法则是您要减小子树的大小(意思是第二级及以上)!所以你想把最明显的值放在第一位。 这些索引看起来很适合 index compression。 @haki 这不是 B 树的工作方式。如果您将更具选择性的列放在复合索引的首位,您实际上不会减少节点数。顶部没有“第一列的 B-Tree 级别”,下方没有“第二列的级别”等......事实上,将选择性较低的列放在首位有助于 Oracle 索引压缩,并且可以在物理上以更有利的方式对索引进行排序方式(取决于您要如何查询)。引用 Tom Kyte 的话:“至少从第 6 版开始,最好先选择最好的就不是事实了。” 【参考方案1】:

索引与它们正在索引的字段相关联,按照它们在索引中定义的顺序。只要您按照从左到右的顺序使用索引中的字段,那么索引就可用于您的查询。如果您要跳过字段,则无法使用索引。例如给定以下索引:

CREATE INDEX ind1 ON foo (bar, baz, qux)

那么这些where子句就可以使用索引了:

WHERE bar=1
WHERE bar=1 AND baz=2
WHERE baz=2 AND bar=1  <--same as before
WHERE bar=1 AND baz=2 AND qux=3

您在查询中使用索引字段的顺序无关紧要,只是您正在使用它们。但是,它们在索引中定义的顺序至关重要。以下子句不能使用索引:

WHERE baz=2  <-- 'bar' not being used
WHERE baz=2 AND qux=3  <-- 'bar' again not being used
WHERE bar=1 AND qux=3  <-- the index can be partially used to find `bar`, but not qux.

对于您的两种情况,它们的索引方式并没有什么问题,但按如下方式索引会稍微更有效:

(STORE_ID, DIST_ID)
(DIST_ID)

在第二个索引中索引 store_id 没有意义,因为 DBMS 可以使用第一个索引来处理 store_id 查找。这不是一个主要的收获,但仍然......维护索引是数据库的开销,而减少开销总是一件好事。

【讨论】:

+1 - 不过,您忽略了索引跳过扫描。您的第二组子句可以使用索引。但它必须是效率较低的跳过扫描(特别是随着前导列中不同值的数量增加),而不是更有效的范围扫描。 另外,最后的陈述并不完全正确。 (store_id, dist_id) 索引对于像 dist_id = xxx and store_id &lt; 10 这样的查询不是最有效的。另一方面,这是为dist_id, store_id 找到的。 “减少开销总是一件好事” - 除非节省的额外开销here导致there性能不佳>. 感谢所有 cmets。现在这个概念对我来说更清楚了。 “在第二个索引中索引 store_id 没有意义” - 除了cover 查询。【参考方案2】:

如果在索引中找到所有需要的信息,Oracle 就不必接触表段。 在您的情况下,这些索引可以用作快速查找/翻译表 STORE_ID => DIST_ID,反之亦然。

只需查看查询的执行计划,其中您选择仅基于 DIST_ID 选择 STORE_ID, 查询只会通过索引,不会触及表本身。

但也许原因不同(如果有的话)。

【讨论】:

以上是关于相同列上的 Oracle 2 索引但顺序不同的主要内容,如果未能解决你的问题,请参考以下文章

mysql重复索引冗余索引未使用索引的定义和查找

聚集索引非聚集索引

where条件顺序与建索引顺序

具有不同排序方向的多列上的Sql server聚集索引

怎么取消自增列上的聚集索引

没有得到相同的 ArrayList 顺序