前缀为“%”的 LIKE 运算符中的索引丢失

Posted

技术标签:

【中文标题】前缀为“%”的 LIKE 运算符中的索引丢失【英文标题】:Loss of index in LIKE operator with prefix "%" 【发布时间】:2019-07-11 18:16:42 【问题描述】:

PL/SQL Developer - Oracle10g

我有一个查询在使用 LIKE 运算符设置时丢失索引,但只有前缀“%”

例如:

select * from people where name like '%POTATO'

它在优化器目标的表中返回“访问完全”。 如何获得轮廓解决方案?

【问题讨论】:

你如何找到一本书中所有以 POTATO 结尾的词条?索引不会以有用的顺序显示它们。如果幸运的话,您也许可以扫描整个索引,手动挑选出所有匹配的单词,然后按照这些索引条目查找实际的书籍文本。但是对于一本小书和一个相对较大的索引,通读整本书并查看每个单词可能会更快,这基本上是 Oracle 的优化器在这里选择做的事情。 “轮廓解决方案”是什么意思?此外,您可能想要调查 Oracle Text。如果这是您可能经常做的事情,您可以考虑基于反转文本的基于函数的索引,然后您可以使用“OTATOP%”进行搜索,但这可能会产生很多开销。 "当您使用LIKE 在索引列中搜索模式时,如果模式中的前导字符不是% 或@987654325,Oracle 可以使用索引来提高查询性能@. 在这种情况下,Oracle 可以通过这个前导字符来扫描索引。如果模式中的第一个字符是%_,那么索引无法提高性能,因为 Oracle 无法扫描索引。 from Oracle documentation. 我喜欢第一条评论,我没有意识到索引是这样工作的。 【参考方案1】:

如果您认为通过这种特殊名称结尾进行查询非常重要,请考虑创建一个function-based 索引:

create index idx_special_people
on people(upper(substr(name,-6)));

收集表格统计信息:

exec dbms_stats.gather_table_stats(user, 'people', cascade => true);

并调用:

select * 
  from people 
 where upper(substr(name,-6)) = 'POTATO'

【讨论】:

【参考方案2】:

优化器将花费各种方法,包括全表扫描和索引全扫描。据推测,它的计算表明全表扫描会更有效。这很可能是因为您必须全面扫描整个索引才能找到以“POTATO”结尾的键,而以“POTATO”开头的键被存储在一起(就像在电话簿中一样)。

如果您分享表和索引的详细信息、数据量和执行计划,也许有人可以提供更详细的建议。

【讨论】:

【参考方案3】:

您可以尝试使用提示:

select /*+ INDEX(people indexname) */ * from people where name like '%POTATO'

【讨论】:

做或不做 - 没有“尝试”。 "当您使用LIKE 在索引列中搜索模式时,如果模式中的前导字符不是% 或@987654325,Oracle 可以使用索引来提高查询性能@. 在这种情况下,Oracle 可以通过这个前导字符扫描索引。如果模式中的第一个字符是%_,那么索引无法提高性能,因为 Oracle 无法扫描索引。 from Oracle documentation. 是的@MT0 我也读过,虽然我遇到了类似的问题。我仍然使用 INDEX 提示获得了更好的结果,并且解释计划显示它已被使用。由于没有多少情况下我遇到过这样的问题并且它有效,所以我没有费心去深入研究。 Guess Oracle 会自动删除索引,但只能扫描索引并匹配它,并通过对那个字段发出不同的比较来获得更好的性能。所以我想它在范围扫描方面可能是有益的,但仍然必须对唯一索引进行全面扫描。因为它给了我 3 秒和 60 秒的时间,所以我不在乎文档说什么。 无法提高性能”可能有点无益。 Oracle 无法确定它是否会提高性能,并且由于它经常/通常不会并且可能更糟,它必须忽略索引。您实际上是在强制进行全索引扫描,而不是全表扫描,有时这可能仍然更快 - 只要您最终获得相对较少的命中和如此低的表行访问(与任何索引使用一样)。没有警告,这是一个不好的建议,危险是有人会尝试,看到索引被使用,并假设它实际上不适合他们时是好的。这取决于数据, 是的,但是解释计划会告诉你会发生什么。如果 OP 的 name 字段有 10 个不同的值,并且每个值都链接到 100 万行,那么执行 INDEX 扫描会快得多,将其与 LIKE 条件匹配并返回 100 万行,而不是扫描所有 1000 万行。所以它可以提高性能。根据我们获得的信息,我无法告诉他更多信息,但如果这能提高他的表现,他可以尝试。

以上是关于前缀为“%”的 LIKE 运算符中的索引丢失的主要内容,如果未能解决你的问题,请参考以下文章

Jet/ACE 是不是使用带有 LIKE BeginsWith 查询的索引?

PostgreSQL hstore:使用索引提高LIKE性能?

mysql怎么用like检索字段中带有数字的语句?

如何将 IN 运算符与 LIKE 条件相结合(或获得可比较结果的最佳方法)

如何在 Cassandra 3.7 中使用 LIKE 运算符查询“%”字符?

mysql索引总结