为 Group By 字段创建索引?

Posted

技术标签:

【中文标题】为 Group By 字段创建索引?【英文标题】:Creating Indexes for Group By Fields? 【发布时间】:2010-11-29 12:37:50 【问题描述】:

Oracle 数据库中是否需要为 group by 字段的字段创建索引?

例如:

select * 
from some_table
where field_one is not null and field_two = ?
group by field_three, field_four, field_five

我正在测试我为上面创建的索引,与此查询唯一相关的索引是为 field_two 创建的索引。在任何其他字段上创建的其他单字段或复合索引将不会用于上述查询。这听起来对吗?

【问题讨论】:

【参考方案1】:

这可能是正确的,但这取决于您拥有多少数据。通常我会为我在 GROUP BY 中使用的列创建一个索引,但在您的情况下,优化器可能已经决定,在使用 field_two 索引之后,没有足够的数据返回来证明使用 GROUP 的另一个索引是合理的由。

【讨论】:

+1 提到了优化器,这可能是最可能的原因。 感谢您的回复。我没有意识到解释计划取决于表中的数据量。目前表中没有数据,这就解释了为什么优化器可能已经跳过了其他索引。另一方面,仅在 field_three 和 field_four 上没有 field_five 的复合索引是否仍可用于上述查询?这不会包括 group by 子句中的所有字段。 @Mark - 这解释了它。有关 Oracle 可用于分组依据的索引的更多信息,请参阅我的编辑。 @jva - 不确定分组顺序与优化器相关是什么意思。它仅与可以使用哪些索引有关。基本上,索引中列的顺序应该与 group by 子句中的列顺序相同。 @Eric:在我看来,GROUP BY 顺序对 Oracle 来说不太重要。更改 GROUP BY 中列的顺序不会更改查询的语义,因此不应更改计划。证明?【参考方案2】:

不,这可能不正确。

如果您有一个大表,Oracle 可以更喜欢从索引而不是从表中派生字段,即使没有涵盖所有值的单个索引。

在我博客的最新文章中:

NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL: Oracle

,有一个查询Oracle不使用全表扫描而是连接两个索引来获取列值:

SELECT  l.id, l.value
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  value
        FROM    t_right r
        WHERE   r.value = l.value
        )

计划是:

SELECT STATEMENT
 HASH JOIN ANTI
  VIEW , 20090917_anti.index$_join$_001
   HASH JOIN
    INDEX FAST FULL SCAN, 20090917_anti.PK_LEFT_ID
    INDEX FAST FULL SCAN, 20090917_anti.IX_LEFT_VALUE
  INDEX FAST FULL SCAN, 20090917_anti.IX_RIGHT_VALUE

如您所见,这里的t_left 上没有TABLE SCAN

相反,Oracle 获取 idvalue 上的索引,将它们连接到 rowid 并从连接结果中获取 (id, value) 对。

现在,您的问题:

SELECT  *
FROM    some_table
WHERE   field_one is not null and field_two = ?
GROUP BY
        field_three, field_four, field_five

首先,它不会编译,因为您从带有GROUP BY 子句的表中选择*

您需要将* 替换为基于分组列和非分组列聚合的表达式。

您很可能会从以下索引中受益:

CREATE INDEX ix_sometable_23451 ON some_table (field_two, field_three, field_four, field_five, field_one)

,因为它将包含在field_two 上进行过滤、在field_three, field_four, field_five 上排序(对GROUP BY 有用)并确保field_oneNOT NULL 的所有内容。

【讨论】:

非常有趣——我想我以前从未见过这种情况(Oracle 会加入两个索引并完全避免使用该表) @Eric Petroelje:有一个特殊的提示,INDEX_JOIN,强制这个方法。【参考方案3】:

Oracle 数据库中是否需要为 group by 字段的字段创建索引?

没有。您不需要这样做,因为无论是否存在任何索引,查询都会运行。提供索引以提高查询性能。

但是,它可以提供帮助;但是我会犹豫添加索引只是为了帮助一个查询,而不考虑新索引对数据库的可能影响。

...此查询的唯一相关索引是为 field_two 创建的索引。在任何其他字段上创建的其他单字段或复合索引将不会用于上述查询。这听起来对吗?

并非总是如此。通常 GROUP BY 将要求 Oracle 执行排序(但并非总是如此);您可以通过在要排序的列上提供合适的索引来消除排序操作。

但是,您是否真的需要担心 GROUP BY 的性能,这是您需要考虑的一个重要问题。

【讨论】:

赞成“可以消除排序操作..”。 BTW这篇文章有更多细节use-the-index-luke.com/sql/sorting-grouping/indexed-group-by

以上是关于为 Group By 字段创建索引?的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver group by 非聚集多字段组合索引性能慢的问题

SQL中查询多个字段时,GROUP BY 要怎么使用?

MySQL没有使用SUM中的索引和GROUP BY查询

GROUP BY中的字段是否必须在SELECT中

GROUP BY中的字段是否必须在SELECT中

对单个字段的结果进行去重,用distinct执行效率快,还是用group by快