暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

Oracle 总结:为什么不走索引(二)

原创 布衣 2023-11-05
1422

背景

  书接上回Oracle 总结:为什么不走索引(一)

情况4:

  • 数据库隐式使用函数原因与情况3相同
    我们创建了一个字符列的索引,但这个列中只存放了一些数值数据。下面的查询就不走索引
select * from t where indexed_column=5

– 注意:这个查询中指定的常量是数值5.这个查询等价于以下查询

select * from t where to_number(indexed_column)=5

  数据库会对这个列隐式地使用一个函数,所以查询就不能再用索引了。
示例:

SQL>create table t (x char(1) constraint t_pk primary key); SQL>insert into t values('5'); SQL>set autotrace traceonly explain; SQL>select * from t where x=5;

image.png
  即使给这个查询加上提示,强制它使用索引,数据库也不会按照我们原来设想的那样对索引使用union scan ,而是对这个索引进行full scan:
image.png
  因为它必有将X中存储的字符串转换为数字,才能与数值5进行比较。我们不能把数字5转换成字符5,因为数据库的NLS设置会对转成的字串样式有所影响(也就是转换的结果不是确定性的,不同的NLS设置产生不同的字符串),所以我们只能把字符串转成数字,而这样一来(由于应用了函数),数据库就无法使用索引了。
  此例子得出一个结论:一定要尽可能地避免隐式转换。另外如果可能的话,尽量不要在SQL语句的谓词部分对数据库列使用函数。

情况5

  如果用了索引,数据库的处理速度反而会变慢。这种情况比较常见,Oracle (对CBO而言)只在需要的时候才使用索引。

SQL>create table t (x int); SQL>insert into t select rownum from dual connect by level < 1000000; 999999 rows created. SQL>create index t on t(x); SQL>exec dbms_stats.gather_table_stats(user,'T'); SQL>set autotrace traceonly explain -- 如果我们的查询只取表中的少量数据: SQL>select count(*) from t where x< 50;

image.png
  此时优化器很乐意使用索引。不过我们发现,如果优化器估计通过索引取得的数据超过一个阀值(取决于不同的优化器设计、物理统计等,这个阀值可能有所变化),它就会进行全表扫描。

SQL>select count(*) from t where x<500000;

image.png
  这个例子显示出优化器不一定会使用索引;查询优化器在这里使用全表扫描是个正确的选择。当你进行调优时,如果发现那个查询没有使用你认为应该用到的索引,不要贸然强制使用这个索引,应该先做个测试,证明使用这个索引后确实会加快速度(通过比较耗用时间和I/O次数等),然后再考虑让CBO就范(强制它使用这个索引)。

情况6:

  表上的统计信息过旧也会影响查询使用索引,所以一般没走索引先收集下统计信息也能解决问题。

总结:

  数据库不使用索引原因一般为建的索引与使用的条件不一致,要不就是走索引比走全表更耗时(需要进行测试验证来确诊),要不就是走索引不能得到正确的答案。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论