暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

oracle调优之今日索引总结01

原创 晴天 2024-04-09
311


1.oracle访问数据块的方式

当oracle进程需要访问数据文件里的数据块时,oracle会有两种类型的I/O操作方式:

随机访问,每次读取一个数据块(通过等待事件“db file sequential read”体现出来)。

顺序访问,每次读取多个数据块(通过等待事件“db file scattered read”体现出来)。

第一种方式则是访问索引里的数据块,而第二种方式的I/O操作属于全表扫描。

当oracle需要获得一个索引块时,首先从根节点开始,根据所要查找的键值,从而知道其所在的下一层的分支节点,然后访问下一层的分支节点,再次同样根据键值访问再下-层的分支节点,如此这般,最终访问到最底层的叶子节点。可以看出,其获得物理 I/0 块时,是一个接着一个,按照顺序,串行进行的。在获得最终物理块的过程中,我们不能同时读取多个块,因为我们在没有获得当前块的时候是不知道接下来应该访问哪个块的。因此,在索引上访问数据块时,会对应到 db file sequentialread 等待事件,其根源在于我们是按照顺序从一个索引块跳到另一个索引块,从而找到最终的索引块的。

那么对于全表扫描来说,则不存在访问下一个块之前需要先访问上一个块的情况。全表扫描时,orace知道要访问所有的数据块,因此唯一的问题就是尽可能高效的访问这些数据块。因此,这时 oracle 可以采用同步的方式,分几批,同时获取多个数据块。这几批的数据块在物理上可能是分散在表里的,因此其对应到db file scattered read 等待事件。


2.B树索引对于插入(INSERT)的管理

对于B树索引的插入情况的描述,可以分为两种情况:

一种是在一个已经充满了数据的表上创建索引时,索引是怎么管理的;

另一种则是当一行接着一行向表里插入或更新或删除数据时,索引是怎么管理的。

对于第一种情况来说,比较简单。当在一个充满了数据的表上创建索引(createindex 命令)时,oracle 会先扫描表里的数据并对其进行排序,然后生成叶子节点。生成所有的叶子节点以后,根据叶子节点的数量生成若干层级的分支节点,最后生成根节点。这个过程是很清晰的。

第二种情况来说,类似于细胞分裂的过程,当一个细胞容纳不下新的索引信息的时候会进行分裂。

从索引可用列表上获得一个新的索引数据块,将当前满了的分支节点里的索引条目分成两部分,较小键值的部分不动,而较大键值的部分移入新的索引块。将新的索引条目插入合适的分支索引块。在上层分支索引块中添加一个新的索引条目,使其指向新加的分支索引块。

当数据量再次不断增加,导致原来的根节点不足以存放新的索引条目(这些索引条目指向分支节点)时,引起根节点的分裂。同时,根节点分裂以后,索引的层级再次递增。

由此可以看出,根据#树索引的分裂机制,一个#树索引始终都是平衡的。

注意,这里的平衡是指每个叶子节点与根节点的距离都是相同的。

3. B树索引对于删除(DELETE)的管理

与索引相关的一个比较重要的视图 index stats

该视图显示了大量索引内部的信息,该视图正常情况下没有数据,只有在运行了下面的命令以后才会被填充数据,而且该视图中只能存放一条与分析过的索引相关的记录,不会有第二条记录同时,也只有运行了该命令的 session才能够看到该视图里的数据,其他 session 不能看到其中的数据。

analyze index INDEX_NAME validate structure;

不过要注意一点,就是该命令有一个坏处,就是在运行过程中,会锁定整个表,从而阻塞其他 session 对表进行插入、更新和删除等操作。这是因为该命令的主要目的并不是用来填充 index_stats 视图的,其主要作用在于校验索引中的每个有效的索引条目都对应到表里的一行,同时表里的每一行数据在索引中都存在一个对应的索引条目。为了完成该目的,所以在运行过程中要锁定整个表,同时对于很大的表来说,运行该命令需要耗费非常多的时间。

当删除表里的一条记录时,其对应于索引里的索引条目并不会被物理的删除,只是做了一个删除标记。

当一个新的索引条目进入一个索引叶子节点的时候,oracle 会检查该叶子节点里是否存在被标记为删除的索引条目,如果存在,则会将所有具有删除标记的索引条目从该叶子节点里物理的删除。oracle 会将当前所有被清空的叶子节点(该叶子节点中所有的索引条目都被设置为删除标记)收回,从而再次成为可用索引块

尽管被删除的索引条目所占用的空间大部分情况下都能够被重用,但仍然存在一些情况可能导致索引空间

被浪费,并造成索引数据块很多但是索引条目很少的后果,这时该索引可以认为出现碎片。

而导致索引出现碎片的情况主要包括:

不合理的、较高的 PCTFREE。

4.关于答案解析
1)索引应该在 SQL 语句的"where"或"and"部分涉及的表列(也称谓词)被建立。
2)用户应该索引具有一定范围的表列,数据重复且分布平均的表字段不适合建立索引,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
3)如果在SQL语句谓词中多个表列被一起连续引用,则应该考虑将这些表列一起放在一个索引内, Oracle将维护单个表列的索引(建立在单一表列上)或复合索引(建立在多个表列上)。复合索引的建立顺序按照使用的频度来确定。
4)如果多数查询返回结果都超过表中总行数的4%,那么一般不宜建立索引。比如上图中的id列,如果根据id>10的条件查出的结果占总行数的大多数,那么走索引效率<全表扫描。


在Oracle中,为什么索引没有被使用?

表上是否存在索引

检查您认为应该通过索引访问的表上是否真的创建了索引。那些索引可能已经被删掉或者在创建的时候就失败了。例如,种可能的场景是,在对表做导入操作后,由于软件或人为错误造成索引没有被创建。通过DBA_INDEXES视图可以检查索引是否存在。

索引是否应该被使用

orac1e不会仅仅因为有索引存在就一定要使用索引。如果一个查询需要检索出这个表里所有的记录,那么只需要单独访问表的数据会更快。对所有的查询而言,0racie优化器会基于统计信息来计算各种访问路径,包括索引,从而达出最优的-条路径。

索引的索引列是否在 WHERE条件中(Predicate list)

对于单列索引而言,只有当索引列出现在查询的WHERE条件中时,0racle才能使用到索引。对于组合索引而言,如果索引的前置列没有出现在 WHERE条件中,而是用到了组合索引的其它索引列,那么这时候oracle 可能会选择索引跳跃扫描(Index Sxip Scan;INDEX_SS)或不会选择索引扫描。

索引列是否用在连接谓词中(JoinPredicates)

如果索引列是连接谓词的一部分,那么需要查看使用了哪种类型的连接方式?在两张表连接中,且内表的目标列上建有索引时,只有NL连接才能有效地利用到该索引。SMJ即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程。HJ由于须做 HASH 运算,索引的存在对数据查询速度几乎没有影响。

连接顺序(Join order)是否允许使用索引。

查看连接顺序(Join·0xdex)是否允许使用相关索引。假设表A的 ID列上有索引,表B的列 ID上无索引,WHERE 语句有A.ID=B.ID条件,并且查调中没有与A.ID相关的其他谓词。在做NL连接时,表A做为外部表,先被访问,由于连接机制原因,外部表的数据访问方式是全表扫描,A.ID上的索引显然是用不上。

索引列是否在 IN 或者多个 OR 语句中。

如果索引列在 IN或or子句中,那么查询可能已经被转化为不能使用索引的语句。

是否对索引列进行了函数、算术运算或其他表达式等操作

应尽里避免在 WHERE 子句中对索引字段进行函数、算术运算或其他表达式等操作,因为这样可能会使索引失效,查询时要尽可能将操作移至等号右边。

索引列是否出现了隐式类型转换

如果进行比较的两个值的数据类型不同,那么 oracle 必须将其中一个值进行类型转换使其能够比较。这就是所谓的隐式类型转换。通常当开发人员将数字存储在字符列时会导致这种问题的产生。0racle在运行时会在索引字符列使用TO NUMBEF函数强制转化字符类型为数值类型。由于添加函数到索引列所以导致索引不被使用。实际上,0racle也只能这么做,类型转换是一个应用程序设计因素。由于转换是在每行都进行的,这会导致性能问题。一般情况下,当比较不同教据类型的教报时,oracle自动地从复杂向简单的数据类型转换。所以,字符类型的字段值应该加上引号。

是否在语义(semantically)上无法使用索引

出于对查询整体成本的考虑,一个成本较低的执行计划中可能是无法使用索引的。某索引可能已经被考虑在某种连接排序及方法中,但是成本最低的那个执行计划中却无法从“语义”角度使用该索引。

错误类型的索引扫描

可以定义索引的排序顺序为递增或递减。oracle对待降序索引就好像它是基于函数的索引,因此与缺省使用的升序的执行计划不同。通过查看执行计划是看不到使用升序或阵序的,需要额外检查视图DBA_INDCOLUATS的DESCEND 列。如果系统中经常使用索引范围扫猫进行读取数据的话(例如在 WHERE 子句中使用“BETWEEN AND”语句或比较运算符“>”、“<”、“<=”等),那么反向键索引将不会被使用,此时>

索引列是否可以为空

除了联合索引(即多列索引)和位图索引外,其它索引都不存储 NULL值。只有至少有一个索引列有值,联合索引才存储空值。联合索引中尾部的空值也会被存放在索引中。如果所有列的值都为空,这行将不会存緒在索引中。由于索引中缺乏 NULIL值,那么一些结果中可能会返回NULI值(例如,COUNT)的操作可能会被禁用索引。这是因为优化器不能保证在单独使用索引时可以获得准确的信息。位图索引允许存储空值。因此,无论它们的结果可信与否,优化器都会使用这些索引。



文章转载自晴天,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论