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

Oracle 19C 关于B树索引访问

原创 Asher.HU 2021-02-04
575


B树是平衡树的缩写,是最常见的数据库索引类型。

B树索引是值的有序列表分为范围。通过将关键字与行或行范围相关联,B树可为广泛的查询(包括精确匹配和范围搜索)提供出色的检索性能。



8.3.1.1 B树索引结构

B树索引具有两种类型的块:用于搜索的分支块和用于存储值的叶块。

下图说明了B树索引的逻辑结构。分支块存储在两个密钥之间做出分支决策所需的最小密钥前缀。叶块包含每个索引数据值和一个用于定位实际行的相应rowid每个索引条目按(键,行ID)排序叶块被双重链接。

图8-3 B树索引结构


8.3.1.2索引存储如何影响索引扫描

位图索引块可以出现在索引段中的任何位置。

图8-3显示了彼此相邻的叶块。例如,该1-10块在该11-19之前和之后此顺序说明了连接索引条目的链表。但是,索引块不必按顺序存储在索引段中例如,该246-250块可能出现在段中的任何位置,包括紧接在该1-10之前因此,有序索引扫描必须执行单块I / O数据库必须读取一个索引块,以确定下一步必须读取哪个索引块。

索引块主体将索引条目存储在堆中,就像表行一样。例如,如果将值10首先插入表中,则带有键的索引条目10可能会插入到索引块的底部。如果0在表的下一个插入,则键的索引条目0可能会插入的条目的顶部10因此,块主体的索引条目未按键顺序存储。但是,在索引块内,行标题按键顺序存储记录。例如,标题中的第一条记录指向带有key的索引条目0,依此类推,直到指向指向带有key的索引条目的记录。10因此,索引扫描可以读取行标题以确定开始和结束范围扫描的位置,从而避免了读取块中每个条目的必要。

也可以看看:

Oracle Database Concepts了解索引块

 

8.3.1.3唯一索引和非唯一索引

非唯一索引中,数据库通过将rowid作为额外的列附加到键中来存储它该条目添加一个长度字节以使密钥唯一。

例如,图8-3所示的非唯一索引中的第一个索引键是一对,而不是简单的数据库按索引键值然后按rowid升序对数据进行排序。例如,条目的排序如下: 0,rowid0

0,AAAPvCAAFAAAAFaAAa
0,AAAPvCAAFAAAAFaAAg
0,AAAPvCAAFAAAAFaAAl
2,AAAPvCAAFAAAAFaAAm

在唯一索引中,索引键不包含rowid数据库仅由索引键值,诸如排序数据012,等。

也可以看看:

Oracle Database Concepts概述了唯一索引和非唯一索引


8.3.1.4 B树索引和空值

B树索引永远不会存储完全为空的键,这对于优化器如何选择访问路径很重要。此规则的结果是,单列B树索引从不存储空值。


一个例子可以说明。hr.employees表的主键索引为employee_id,唯一索引为department_iddepartment_id列可以包含null,使其成为可为null的列,但该employee_id列不能。

SQL> SELECT COUNT(*) FROM employees WHERE department_id IS NULL;
 
  COUNT(*)
----------
         1
 
SQL> SELECT COUNT(*) FROM employees WHERE employee_id IS NULL;
 
  COUNT(*)
----------
         0


以下示例显示了优化程序选择全表扫描以查询中的所有部门ID hr.employees优化器无法使用索引employees.department_id因为不能保证索引包含表中每一行的条目

SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees;
 
Explained.
 
SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3476115102
 
-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   107 |   321 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |   321 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------
 
8 rows selected.


下面的示例显示了优化程序可以使用索引on department_id来查询特定部门ID,因为所有非空行都已建立索引。

SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees WHERE department_id=10;
 
Explained.
 
SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 67425611
 
--------------------------------------------------------------------------------
| Id| Operation        | Name              | Rows |Bytes| Cost (%CPU)| Time    |
--------------------------------------------------------------------------------
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |                   |   1 |   3 |     1   (0)| 00:0 0:01|
|*1 |  INDEX RANGE SCAN| EMP_DEPARTMENT_IX |   1 |   3 |     1   (0)| 00:0 0:01|
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
 
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------- 
   1 - access("DEPARTMENT_ID"=10)


下面的示例显示了当谓词排除空值时,优化器选择索引扫描

SQL> EXPLAIN PLAN FOR SELECT department_id FROM employees 
WHERE department_id IS NOT NULL;

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1590637672
 
--------------------------------------------------------------------------------
| Id| Operation        | Name              | Rows|Bytes| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |                   | 106 | 318 |    1   (0)| 00:0 0:01 |
|*1 |  INDEX FULL SCAN | EMP_DEPARTMENT_IX | 106 | 318 |    1   (0)| 00:0 0:01 |
--------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
 
   1 - filter("DEPARTMENT_ID" IS NOT NULL)

 



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

评论