1

我在一个包含超过 160 万条记录的表中的 Oracle 11GR2 中有一个简单的搜索存储过程。我很困惑,如果我想在一个列中搜索一个作品,例如“%boston%”,它需要 12 秒。我在名称列上有一个索引。

select description from travel_websites where name like "%boston%";

如果我只搜索以 Boston 开头的单词,例如“boston%”,则只需 0.15 秒。

select description from travel_websites where name like "boston%";

我添加了一个索引提示并尝试强制优化器在名称列上使用我的索引,它也没有帮助。

select description /*+ index name_idx */  from travel_websites where name like "%boston%";

任何建议将不胜感激。

4

2 回答 2

6

您不能对具有前导通配符(即like '%boston%')的谓词使用索引范围扫描。如果您考虑索引如何存储在磁盘上,这是有道理的——如果您不知道要搜索的字符串的第一个字符是什么,则无法遍历索引来查找与该字符串匹配的索引条目. 您可以对读取每个叶块的索引进行全面扫描,并在name那里搜索以查看它是否包含您想要的字符串。但这需要对索引进行全面扫描,然后您必须每次访问该表ROWID您从索引中获取任何不属于您刚刚完全扫描的索引的列。根据表和索引的相对大小以及谓词的选择性,如果您正在搜索前导通配符,优化器可能很容易决定只进行表扫描会更快。

Oracle 确实支持全文搜索,但您必须使用 Oracle Text,这需要您在name列上构建 Oracle Text 索引并使用CONTAINS 运算符进行搜索,而不是使用LIKE查询。Oracle Text 是一个非常强大的产品,因此在构建索引、刷新索引和构建查询时有很多选项需要考虑,具体取决于您想要获得的复杂程度。

您的索引提示未正确指定。假设在 上有一个索引name,该索引的名称是name_idx,并且您想强制对索引进行全面扫描(重申一下,如果存在前导通配符,则对索引进行范围扫描不是有效选项) ,你需要类似的东西

select /*+ index(travel_websites name_idx) */ description
  from travel_websites
 where name like '%boston%'

但是,不能保证全索引扫描会比全表扫描更有效。并且完全有可能优化器已经在没有提示的情况下选择了索引全扫描(您没有指定三个查询的查询计划是什么)。

于 2012-08-29T21:03:50.040 回答
2

默认情况下,Oracle(以及据我所知的大多数其他数据库)索引字符串,以便索引只能用于从字符串开头查找字符串匹配项。这意味着,a LIKE 'boston%'(startswith) 将能够使用索引,而 a LIKE '%boston'(endswith) 或LIKE '%boston%'(contains) 则不能。

如果您确实需要可以快速找到子字符串的索引,则不能对字符串使用常规索引类型,但可以使用TEXT索引,遗憾的是可能需要稍微不同的查询语法。

于 2012-08-29T21:08:35.410 回答