避免将函数应用于索引列

Posted

技术标签:

【中文标题】避免将函数应用于索引列【英文标题】:Avoid applying a function to an index column 【发布时间】:2019-04-18 20:34:26 【问题描述】:

我需要过滤掉超过一定长度的数据,但包含数据的列是索引列。如果我将函数应用于列,我将失去索引的好处。

由于我不是数据库管理员,因此无法创建新索引或更改列。 我不希望事后删除数据。

我知道一些过滤列的方法,但都会使用某种函数。

select
table.name
from 
table
where
length(table.name)>12
;

table.name 字段不可为空。

【问题讨论】:

你有什么问题? “我不是 DBA,因此无法创建新索引”。这是一个糟糕的借口 - 如果只有 DBA 可以创建新索引,并且如果您确实可以提出需要新索引的好案例,那么您将指示 DBA 创建您需要的索引。如果您的很多查询都根据列中字符串的长度进行过滤,那么该列上的基于函数的索引可能会很有帮助,而实际创建它的人并不重要。另一方面,如果只支持一个查询,并且查询不是关键,那么就不要创建索引,让查询尽可能长。 我知道在长度上创建索引将允许我使用不同的索引。我要问的是是否有办法解决这个问题。我试图通过具体问题来避免这样的答案。感谢您的意见。 如果该列中的值大于 12 个字符,您希望它不提取该列还是只希望该列中的前 12 个字符? 查询真的和你发的一样简单,还是还SELECT其他的?如果它像您发布的一样简单,则将使用索引,如果该列声明为NOT NULL。另一方面,如果该列实际上可以为空,则不会使用索引,因为 Oracle 不够聪明,无法对自己说:“如果长度(NAME)> 12 那么 NAME 不能为 NULL,所以我被允许使用索引。” 【参考方案1】:

如果我将函数应用于列,我将失去索引的好处。

啊,但是索引有什么好处呢?

考虑这两个值:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

它们都超过 12 个字符吗?是的。它们是否可能在索引中相邻?当然不是。因此,Oracle 使用索引来查找这些值的唯一方法是对索引执行完全快速扫描并评估每个条目的长度。现在 Oracle 可以做到这一点,但值得吗?

您发布的查询仅选择name。在评论中,您说 name 不可为空。在这种情况下,Oracle 使用索引会很有效,因为不需要读取表记录:索引有足够的信息来满足查询。

但是。

在那条评论中你还说:

查询没那么简单

如果您的实际查询包括投影中的其他列,则数据库必须访问该表才能获取这些值。此时,索引读取的经验法则开始发挥作用:如果查询的结果集大于表中所有行的 1-2%,则执行全表扫描比使用索引更有效。所以表中的记录数量变得相关,尤其是length(name) > 12所在的记录比例。如果 99% 的记录都有短名称,那么完全快速扫描索引可能更有效。但如果只有 90% 的使用率可能会对性能造成致命影响。

同样,如果您的实际查询在 WHERE 子句中应用了其他条件,则执行全表扫描(因为数据库需要读取记录来评估这些过滤器)以使用不同的索引可能会更有效,如果有是合适的。

因此,虽然索引对于您在问题中发布的玩具查询很有用,但它可能对您的实际查询没有帮助,并且确实可能​​导致次优访问路径。

是否根据查询复杂性逐案处理?

是的。答案总是,视情况而定。这就是为什么数据库调优专业人员可以收取他们所做的高额咨询费用的原因。如果您不提供完整的查询,我们可以做的最好的事情是point you at this post which explains to ask performance tuning questions 并祝您好运。

【讨论】:

您提供了一些非常有趣的见解。从我读到的内容中,我的印象是,任何时候应用一个函数,索引都不会被使用。此表在许多查询中使用,通常包含许多表。有问题的字段是案例编号。我会更多地研究解释计划,看看我是否能更多地了解实际发生的事情。【参考方案2】:

如果该列不为 NULL,则 Oracle 可以使用全索引扫描来回答查询。它将需要读取索引中的每一行,以便仅找到长度大于 12 的那些行。如果索引小于表,这比全扫描要快。

您只选择索引列,因此 Oracle 不需要访问该表,而是可以完全从索引中获取结果。如果您要选择该索引中没有的其他列,Oracle 还需要读取首先在索引中找到该行的表行。

如果不添加更合适的索引或以其他方式更改数据库架构,则无法解决此问题。

【讨论】:

以上是关于避免将函数应用于索引列的主要内容,如果未能解决你的问题,请参考以下文章

基于应用于列的标量函数的索引

在 pandas 中将 lambda 函数应用于列失败

将函数应用于多索引多列数据帧的 Pythonic 方法是啥?

如何将函数应用于日期索引的 DataFrame

如何将函数应用于 MATLAB 中矩阵的每一行/列?

将函数应用于两列并将输出映射到新列[重复]