前缀为“%”的 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性能?
如何将 IN 运算符与 LIKE 条件相结合(或获得可比较结果的最佳方法)