我在一个包含超过160万条记录的表中的Oracle 11GR2中有一个简单的搜索存储过程。我很困惑的事实是,如果我想在列中搜索一个工作,例如“%boston%”,则需要12秒。我有一个名称collumn的索引。
select description from travel_websites where name like "%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%";
任何建议都将不胜感激。
答案 0 :(得分:5)
您不能对具有前导通配符(即like '%boston%'
)的谓词使用索引范围扫描。如果您考虑索引如何存储在磁盘上,这是有道理的 - 如果您不知道要搜索的字符串的第一个字符是什么,则无法遍历索引以查找与该字符串匹配的索引条目。您可以对读取每个叶块的索引进行全面扫描,并在那里搜索name
以查看它是否包含您想要的字符串。但是,这需要对索引进行全面扫描,然后您必须访问从索引获取的每个ROWID
的表,以便获取不属于您刚刚完全扫描的索引的任何列。根据表的相对大小和索引以及谓词的选择性,如果您正在搜索前导通配符,优化器可以轻松地决定只执行表扫描。
Oracle does support full text search但您必须使用Oracle Text,这需要您在name
列上构建Oracle Text索引并使用CONTAINS operator进行搜索而不是使用{ {1}}查询。 Oracle Text是非常强大的产品,因此在构建索引,刷新索引和构建查询时,有很多选项可供考虑,具体取决于您希望获得的复杂程度。
未正确指定索引提示。假设LIKE
上有索引,该索引的名称为name
,并且您要强制完全扫描索引(只是重申,索引上的范围扫描不是一个有效的选项,如果有一个前导通配符),你需要像
name_idx
然而,无法保证完整索引扫描比全表扫描更有效。并且完全有可能优化器在没有提示的情况下选择索引全扫描(您没有为这三个查询指定查询计划)。
答案 1 :(得分:2)
Oracle(据我所知大多数其他数据库)默认索引字符串,以便索引只能用于从字符串的开头查找字符串匹配项。这意味着,LIKE 'boston%'
(startswith)将能够使用索引,而LIKE '%boston'
(endswith)或LIKE '%boston%'
(包含)则不会。
如果您确实需要能够快速查找子字符串的索引,则不能对字符串使用常规索引类型,但可以使用TEXT
索引,这可能需要稍微不同的查询语法。