为啥索引不用于某些值?
Posted
技术标签:
【中文标题】为啥索引不用于某些值?【英文标题】:Why index is not used for some values?为什么索引不用于某些值? 【发布时间】:2014-01-29 15:08:56 【问题描述】:我们有包含 email 和 siteId 列的“Customers”表。并且有一个由这两列组成的索引。因此,在通过电子邮件执行查询和过滤时,相关查询总是使用此索引,例如:
select * from customers where email = 'someEmail@gmail.com';
我们可以确保使用了索引,因为我们已经使用解释计划检查了查询。现在,我们昨天有一个有趣的案例。带有子句“email = 'random@gmail.com'”的相同查询根本没有使用索引。解释计划显示 oracle 进行了全面扫描。该表包含数百万条记录,因此这个没有索引的查询达到 30 秒。有趣的部分查询是否将索引与任何其他电子邮件值一起使用(ransom@gmail.com、randon@gmail.com)。oracle 不使用索引的原因是什么?
我的一个原因是索引不包含这样的值,所以首先 oracle 遍历索引然后进行全扫描,但随后解释计划应该显示它执行了索引扫描。在我们的例子中,解释计划只显示完整扫描。另一个原因是它与 db restore 有某种关系,但也不确定索引怎么可能不包含这样的值。
UPDATE 恢复后的所有表的 last_analyzed 日期值为一周前。在电子邮件的这种特殊情况下,由于客户隐私,所有电子邮件在更新后都会更新为一些随机值。客户表有几百万条记录,所以是的,恢复后发生了相当大的变化,但仍然不明白它与不使用电子邮件有什么关系,因为这个客户表在恢复之前已经有数百万条记录。
UPDATE2在我们对表执行收集统计信息后使用索引。
UDATE3 好吧,客户表中的所有电子邮件值都是唯一的,因此 CBO 不太可能决定此类特定电子邮件的行数过多。只是有很多电子邮件具有相同的起始字符“随机...”,但这不应该被视为相同的值,对吧?
【问题讨论】:
表是否包含频繁的插入和删除? 如果没有找到索引命中就不会进行全扫描;它会做一个或另一个,而不是两者兼而有之。 (它是进行全索引扫描还是全表扫描?)假设您的统计数据是最新的,索引是否有直方图,并且您是否有很多与行为不同的地址相似的地址? 我同意 Alex 的观点,这可能是由于特定电子邮件 ID 的基数很高,Oracle 将进行全表扫描。 是在电子邮件更新为随机值之前最后一次收集的统计信息吗?如果是这样,最初可能有很多相似(或相同)的值,而您的更新/随机值恰好与流行的原始选择一致。如果收集统计数据解决了它,那就太好了*8-) 【参考方案1】:服务器不会查看索引中的数据,如果没有找到则扫描表。在它做任何事情之前,它会查看统计信息,看看它是否应该使用索引或扫描表。我猜想,由于某种原因,电子邮件地址通过了,使 oracle 认为扫描表比查看索引更好。有太多因素无法得出准确的结论。查看统计信息Oracle Doc on Stats。您可能会考虑更改索引的统计数据所涵盖的数据量,这会有所帮助。
【讨论】:
从我以looking at histograms 开头的描述来看,作为做出该决定的原因。 @AlexPoole 有趣的东西,谢谢。另请参阅更新后的问题。【参考方案2】:直方图只考虑第一个 32 个字节。相同的起始字符有多大?详情请见this Oracle Optimizer post。
将唯一字符移动到字符串的开头或禁用直方图,如下所示:
begin
dbms_stats.set_table_prefs
(
'<schema>',
'CUSTOMERS',
'METHOD_OPT',
'FOR ALL COLUMNS SIZE AUTO, FOR COLUMNS SIZE 1 EMAIL'
);
end;
/
【讨论】:
有趣的一点,但在我们的例子中,以“random..”开头的电子邮件只包含 6 个相同的字节(随机),所以直方图也应该考虑其他字符。以上是关于为啥索引不用于某些值?的主要内容,如果未能解决你的问题,请参考以下文章