通过 oncheck 理解 Informix 索引结构

引言

在 Informix 中,可以通过索引来快速定位“需要使用的数据行”。那么一般的 Informix 索引是通过什么结构来实现“快速定位数据行”的目的呢?本文将通过 oncheck 命令来展示实际的 Informix 索引结构,为您揭晓这个问题的答案。

Informix 索引简介

在 Informix 中,一个数据表里可能有很多数据行(row)。例如某连锁超市的“客户基本信息”数据表里有 7 百万个数据行(即 7 百万个客户的基本信息)。Informix 收到超市工作人员输入的“某个客户的客户号”后,需要快速的向超市工作人员返回“这个客户的姓名、邮箱、住址等信息”。如果 Informix 收到“某个客户的客户号”后,把“客户基本信息”数据表的 7 百万个数据行从前往后一行一行顺序扫描,那么 Informix 将无法快速返回结果。如何才能达到“快速返回结果”的目的呢?答案是使用 Informix 索引。Informix 索引就像是中文字典里的拼音目录。拼音目录里记录了每个拼音和对应的页码,Informix 索引里记录了每个特征值(例如每个客户的客户号)和对应的数据行地址。通过拼音目录可以快速的得到某个拼音对应的页码,通过 Informix 索引可以快速的得到某个特征值(例如某个客户的客户号)对应的数据行地址。

在 Informix 中一般的索引是通过 B+ 树这种数据结构来实现的。B+ 树是一种树结构,它的每个节点可以有多个分叉。B+ 树可以是 1 层或多层。在 B+ 树中,所有的叶节点都在同一层,即不会出现类似这样的情况:在一棵 B+ 树中,有的叶节点在第 2 层,有的叶节点在第 3 层。关于 B+ 树的详细叙述请参看 Wikipedia 上关于 B+ 树的内容。B+ 树的结构如图 1 所示。

图 1. 图 1. B+ 树的结构

B+ 树的结构

图 1 中的 B+ 树一共有 3 层:第 1 层是根节点,第 2 层是分支节点,第 3 层是叶节点。节点里有多个节点项 (entry),每个节点项由键 (key) 和值 (value) 组成。节点项的键一般为整数、字符串或“ ‘元素是整数或字符串’ 的集合”。在图 1 的节点中,节点项的键为整数。节点项的值 (value) 一般为指针。在非叶节点中,节点项的值指向子节点。在叶节点中,节点项的值为空指针或指向具体数据的指针。在图 1 的叶节点中,节点项的值指向数据行。一般情况下,每个节点还有两个指针,分别指向“前一个兄弟节点”和“后一个兄弟节点”。

Informix 索引对应的 B+ 树一般是 2 层、3 层或 4 层。

在 Informix 索引对应的 B+ 树中,1 个节点是 1 个页 (page)。

oncheck 命令的简介

在 Informix 中,oncheck 命令可以检查和打印数据对象。例如:

  1. oncheck -cr 可以检查数据库保留页的正确性
  2. oncheck -cD <databaseName>:<tableName> 可以检查数据的正确性
  3. oncheck -cI <databaseName>:<tableName>#<indexName> 可以检查索引的正确性
  4. oncheck -pe <dbsName> 可以打印某个 dbspace 中所有 extent 的分布情况
  5. oncheck -pP <chunkNum> <startPageNum> <numOfPages> 可以打印指定的数据页
  6. oncheck -pT <databaseName>:<tableName> 可以打印“某个数据表以及其上的索引”的磁盘使用情况

关于 oncheck 命令的详细叙述请参看 Informix Information Center 中关于 oncheck 的内容

准备工作

本文通过一个例子来讲述“如何通过 oncheck 命令来展示 Informix 索引结构”。通过以下步骤来创建这个例子所需的数据对象:

扫描二维码关注公众号,回复: 5825151 查看本文章

(1)首先通过如下的 SQL 语句在名为 dbs1 的 dbspace 中创建数据库 db1:

1

create database db1 in dbs1 with log;

(2)然后使用如下的 SQL 语句在 db1 中创建数据表、加载数据、创建索引:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

create table employee (

 employeenum int,

 deptnum int,

 profnum int,

 band int,

 name char(10),

 description varchar(200)

);

create procedure employeeProc()                                     

define my_employeenum integer;

define my_deptnum integer;

define my_profnum integer;

define my_band integer;

define my_name char(10);

define my_description varchar(200);

let my_profnum = 1;

let my_band = 0;

for my_employeenum = 1 to 60000

let my_deptnum = my_employeenum / 5 + 1;

let my_band = my_band + 1;

if (my_band = 51) then

 let my_band = 1;

 let my_profnum = my_profnum + 1;

end if;

let my_name = 'name' || my_employeenum;

let my_description = 'Description of employee ' || my_employeenum ||

                    ': she/he is an excellent employee.';

insert into employee values

(my_employeenum, my_deptnum, my_profnum, my_band, my_name, my_description);

end for;

end procedure;

call employeeProc();

create unique index idx1 on employee ( employeenum );

create index idx2 on employee ( deptnum );

create unique index idx3 on employee ( profnum, band );

上面的 SQL 语句创建了名为 employee 的数据表,该数据表有 6 个数据列:employeenum 是员工号,deptnum 是部门号,profnum 是职业种类号,band 是职业等级,name 是员工姓名,description 是对员工的描述。上面的 SQL 语句使用存储过程 employeeProc 往数据表 employee 中插入了 60000 行实验数据。这 60000 行实验数据如表 1 所示。

表 1. 表1. 数据表 employee 中的数据的示例

employeenum deptnum profnum band name description
1 1 1 1 name1 Description of employee 1: she/he is an excellent employee.
2 1 1 2 name2 Description of employee 2: she/he is an excellent employee.
3 1 1 3 name3 Description of employee 3: she/he is an excellent employee.
4 1 1 4 name4 Description of employee 4: she/he is an excellent employee.
5 2 1 5 name5 Description of employee 5: she/he is an excellent employee.
6 2 1 6 name6 Description of employee 6: she/he is an excellent employee.
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
60000 12001 1200 50 name60000 Description of employee 60000: she/he is an excellent employee.

(若要查看全部 60000 行实验数据,请参看文件 employee.txt。文件 employee.txt 被包含在附件“Informix 索引结构 .zip”中。)

在数据表 employee 上有 3 个索引:idx1、idx2、idx3。idx1 是单列唯一索引(single-column unique index)。idx2 是单列非唯一索引(single-column non-unique index)。idx3 是多列唯一索引(multi-column unique index)。“单列”意味着索引是建在 1 个数据列上。“多列”意味着索引是建在多个数据列上。“唯一”是指任意两个数据行的索引键不能相同,例如对于唯一索引 idx1,任意两个数据行的 employeenum 不能相同。“非唯一”是指两个数据行的索引键可以相同。

单列唯一索引的结构

我们先来关注单列唯一索引 idx1。如何查看 idx1 的内部结构呢?答案是使用 oncheck 命令。我们使用 oncheck -pT 来查看 idx1 的层次,使用 oncheck -pP 来查看 idx1 的所有节点的内容,具体操作如下(这些 oncheck 命令的语法请参看前文的“oncheck 命令的简介”这一章):

  1. 使用如下命令将“数据表 employee 以及其上的索引”的磁盘使用情况输出到文件 pT.out 中:

    1

    oncheck -pT db1:employee > pT.out

    (文件 pT.out 被包含在附件“Informix 索引结构 .zip”中)

  2. 使用如下命令将 dbs1(dbs1 是“employee、idx1、idx2、idx3”所在的 dbspace)中所有 extent 的信息输出到文件 pe.out 中:

    1

    oncheck -pe dbs1 > pe.out

    (文件 pe.out 被包含在附件“Informix 索引结构 .zip”中)

  3. 在文件 pe.out 中,可以看到如下信息:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    ... ...

    ... ...

    Chunk  Pathname                        Pagesize(k)  Size(p)  Used(p)  Free(p)

    10     /opt/ts/dbs/dbs1                     2       500000   6015     493985

    Description                                                   Offset(p)  Size(p)

    ... ...

    ... ...  

    db1:'informix'.idx1                                               4607     512

    ... ...

    ... ...

    这说明索引 idx1 由一个 extent 组成 ( 一个 extent 是一组物理上连续的页 ),idx1 所在的 chunk 的 chunk 号是 10,idx1 的起始页在 chunk 内的页地址为 4607,idx1 的总页数为 512。(chunk 号和 chunk 内的页地址组成物理页地址,所以 idx1 的起始页的物理页地址是 10:4607。)于是我们使用如下命令将 idx1 的内容输出到文件 idx1.out 中:

    1

    oncheck -pP 10 4607 512 > idx1.out

    (文件 idx1.out 被包含在附件“Informix 索引结构 .zip”中)

idx1 的层次

从 pT.out 文件中,我们可以看到 idx1 的层次结构如下:

1

2

3

4

5

6

7

8

                Average    Average

Level    Total No. Keys Free Bytes

----- -------- -------- ----------

    1        1        3       1988

    2        3      144        293

    3      432      138        214

----- -------- -------- ----------

Total      436      138        219

idx1 共有 3 层:第 1 层有 1 个节点,该节点是 idx1 的根节点,该节点有 3 个索引项;第 2 层有 3 个节点,这些节点是 idx1 的分支节点,平均每个分支节点有 144 个索引项;第 3 层有 432 个节点,这些节点是 idx1 的叶节点,平均每个叶节点有 138 个索引项。

idx1 的根节点

在文件 idx1.out 中一共有 512 个页。其中哪一页是 idx1 的根节点呢?

在索引中,逻辑页地址为 0 的页(即起始页)是空白页,逻辑页地址为 1 的页是根节点。(一个页的逻辑页地址表示:从起始页(即第 0 页)算起,该页在逻辑上是第几页。)

如果 idx1 由一个 extent 组成 ( 一个 extent 是一组物理上连续的页 ),那么“页地址转换公式”如下:

1

2

当 1 个索引是由 1 个 extent 组成时的页地址转换公式:

    索引节点的物理页地址 = 索引的起始页的物理页地址 + 索引节点的逻辑页地址

由于 idx1 的起始页的物理页地址为 10:4607(请参看本章“单列唯一索引的结构”的开头部分),idx1 的根节点的逻辑页地址为 1,所以 idx1 的根节点的物理页地址为 10:4608。

在文件 idx1.out 中,可以看到物理页地址为 10:4608 的页(即 idx1 的根节点)的内容如图 2 所示。

图 2. 图 2. idx1 的根节点的内容

idx1 的根节点的内容

在图 2 中,1 个 slot 是 1 个索引项。idx1 的根节点有 3 个 slot,因此 idx1 的根节点有 3 个索引项。第 1 个索引项的键 (key) 为 0x51fd,值 (value) 为 0x3,这说明“第 1 个索引项指向的索引页”的逻辑页地址为 0x3,也就是说“根节点的第 1 个子节点”的逻辑页地址为 0x3。第 2 个索引项的键 (key) 为 0xa3fa,值 (value) 为 0x9c,这说明“第 2 个索引项指向的索引页”的逻辑页地址为 0x9c,也就是说“根节点的第 2 个子节点”的逻辑页地址为 0x9c。第 3 个索引项由于是根节点的最后一个索引项,所以没有键 (key),只有值 (value)。第 3 个索引项的值 (value) 为 0x134,这说明“第 3 个索引项指向的索引页”的逻辑页地址为 0x134,也就是说“根节点的第 3 个子节点”的逻辑页地址为 0x134。

在图 2 的右上部分,可以看到 next 和 prev。next 表示后一个兄弟节点的逻辑页地址,next 的值为 0 表示没有后一个兄弟节点;prev 表示前一个兄弟节点的逻辑页地址,prev 的值为 0 表示没有前一个兄弟节点。由于根节点没有兄弟节点,所以在根节点中 next 的值和 prev 的值都为 0。

idx1 的分支节点

在 idx1 的第 2 层有 3 个分支节点。这 3 个分支节点是 idx1 的根节点的子节点。

下面我们以 idx1 的第 1 个分支节点(即根节点的第 1 个子节点,为叙述方便,下文简称为分支节点 B)为例来讲述 idx1 的分支节点。

在上一节中,我们已经知道分支节点 B(即根节点的第 1 个子节点)的逻辑页地址为 0x3,根据上一节提到的“页地址转换公式”,可以得知分支节点 B 的物理页地址为 10:4610。

在文件 idx1.out 中,可以看到物理页地址为 10:4610 的页(即分支节点 B)的内容如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

addr             stamp    chksum nslots flag type         frptr frcnt next     prev

10:4610          110571078 3ad9   151    850  BTREE        1232  208   9c       0    

    slot ptr   len   flg

    1    24    8     0 

    2    32    8     0 

    3    40    8     0 

    4    48    8     0 

    5    56    8     0 

    6    64    8     0 

    7    72    8     0

    ... ...

    ... ...

    150  1216  8     0 

    151  1224  8     0 

slot   1:

   0: 80  0  0 8b  0  0  0  2                           ................

slot   2:

   0: 80  0  1 16  0  0  0  4                           ................

slot   3:

   0: 80  0  1 a1  0  0  0  5                           ...!............

slot   4:

   0: 80  0  2 2c  0  0  0  6                           ...,............

slot   5:

   0: 80  0  2 b7  0  0  0  7                           ...7............

slot   6:

   0: 80  0  3 42  0  0  0  8                           ...B............

slot   7:

   0: 80  0  3 cd  0  0  0  9                           ...M............

... ...

... ...

slot 150:

   0: 80  0 51 72  0  0  0 98                           ..Qr............

slot 151:

   0: 80  0 51 fd  0  0  0 99                           ..Q}............

从上面的分支节点 B 的内容中,可以看到分支节点 B 一共有 151 个索引项(即 151 个 slot)。每个索引项都有键 (key) 和值 (value),索引项的值指向一个叶节点。例如:第 1 个索引项的键 (key) 为 0x8b,值 (value) 为 0x2,这说明“第 1 个索引项指向的索引页”的逻辑页地址为 0x2,也就是说“分支节点 B 的第 1 个子节点”的逻辑页地址为 0x2;第 151 个索引项的键 (key) 为 0x51fd,值 (value) 为 0x99,这说明“第 151 个索引项指向的索引页”的逻辑页地址为 0x99,也就是说“分支节点 B 的第 151 个子节点”的逻辑页地址为 0x99。

从上面的分支节点 B 的内容中,还可以看到:next 的值为 9c,prev 的值为 0。这表明分支节点 B 的下一个兄弟节点的逻辑页地址为 0x9c,分支节点 B 没有上一个兄弟节点。

“idx1 的其它分支节点”与分支节点 B 的结构相同。

idx1 的叶节点

在 idx1 的第 3 层有 432 个叶节点。这 432 个叶节点是 idx1 的分支节点的子节点。

下面我们以 idx1 的第 1 个叶节点(即分支节点 B 的第 1 个子节点,为叙述方便,下文简称为叶节点 L)为例来讲述 idx1 的叶节点。

在上一节中,我们已经知道叶节点 L(即分支节点 B 的第 1 个子节点)的逻辑页地址为 0x2,根据“idx1 的根节点”这一节提到的“页地址转换公式”,可以得知叶节点 L 的物理页地址为 10:4609。

在文件 idx1.out 中,可以看到物理页地址为 10:4609 的页(即叶节点 L)的内容如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

addr             stamp    chksum nslots flag type         frptr frcnt next     prev

10:4609          110570306 3fde   139    890  BTREE        1275  213   4        0    

    slot ptr   len   flg

    1    24    9     0 

    2    33    9     0 

    3    42    9     0 

    4    51    9     0 

    5    60    9     0 

    6    69    9     0 

    7    78    9     0

    ... ...

    ... ...

    138  1257  9     0 

    139  1266  9     0 

slot   1:

   0: 80  0  0  1  0  0  1  1  0                        ................

slot   2:

   0: 80  0  0  2  0  0  1  2  0                        ................

slot   3:

   0: 80  0  0  3  0  0  1  3  0                        ................

slot   4:

   0: 80  0  0  4  0  0  1  4  0                        ................

slot   5:

   0: 80  0  0  5  0  0  1  5  0                        ................

slot   6:

   0: 80  0  0  6  0  0  1  6  0                        ................

slot   7:

   0: 80  0  0  7  0  0  1  7  0                        ................

... ...

... ...

slot 138:

   0: 80  0  0 8a  0  0  7 12  0                        ................

slot 139:

   0: 80  0  0 8b  0  0  7 13  0                        ................

从上面的叶节点 L 的内容中,可以看到叶节点 L 一共有 139 个索引项(即 139 个 slot)。每个索引项都有键 (key) 和值 (value),索引项的值指向一个数据行。例如:第 1 个索引项的键 (key) 为 0x1,值 (value) 为 0x101,这说明“第 1 个索引项指向的数据行”的 ROWID(数据行 ID)为 0x101;第 139 个索引项的键 (key) 为 0x8b,值 (value) 为 0x713,这说明“第 139 个索引项指向的数据行”的 ROWID(数据行 ID)为 0x713。

从上面的叶节点 L 的内容中,还可以看到:next 的值为 4,prev 的值为 0。这表明叶节点 L 的下一个兄弟节点的逻辑页地址为 0x4,叶节点 L 没有上一个兄弟节点。

“idx1 的其它叶节点”与叶节点 L 的结构相同。

idx1 结构的示意图

根据 idx1 的各节点的内容,可以得出 idx1 的结构如图 3 所示。

图 3. 图 3. 单列唯一索引 idx1 的结构

单列唯一索引 idx1 的结构

单列非唯一索引的结构

单列非唯一索引和单列唯一索引在内部结构上的区别主要是叶节点:在单列非唯一索引的叶节点中,每个索引项包含 1 个键 (key) 和“1 或多个值 (value)”;在单列唯一索引的叶节点中,每个索引项包含 1 个键 (key) 和“1 个值 (value)”。

下面以“单列非唯一索引 idx2 的第 1 个叶节点”为例来说明单列非唯一索引的叶节点。

idx2 的第 1 个叶节点的内容如下(获取“idx2 的第 1 个叶节点的内容”的过程与获取“idx1 的第 1 个叶节点的内容”的过程相似):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

addr             stamp    chksum nslots flag type         frptr frcnt next     prev

10:5121          110573127 24db   55     890  BTREE        1614  210   4        0      

    slot ptr   len   flg

    1    24    24    0 

    2    48    29    0 

    3    77    29    0 

    4    106   29    0 

    5    135   29    0 

    6    164   29    0 

    7    193   29    0

    ... ...    

    ... ...

    54   1556  29    0 

    55   1585  29    0 

slot   1:

   0: 80  0  0  1  0  0  1  1  0  0  0  1  2  0  0  0   ................

  16:  1  3  0  0  0  1  4  0                           ................

slot   2:

   0: 80  0  0  2  0  0  1  5  0  0  0  1  6  0  0  0   ................

  16:  1  7  0  0  0  1  8  0  0  0  1  9  0            ................

slot   3:

   0: 80  0  0  3  0  0  1  a  0  0  0  1  b  0  0  0   ................

  16:  1  c  0  0  0  1  d  0  0  0  1  e  0            ................

slot   4:

   0: 80  0  0  4  0  0  1  f  0  0  0  1 10  0  0  0   ................

  16:  1 11  0  0  0  1 12  0  0  0  1 13  0            ................

slot   5:

   0: 80  0  0  5  0  0  1 14  0  0  0  2  1  0  0  0   ................

  16:  2  2  0  0  0  2  3  0  0  0  2  4  0            ................

slot   6:

   0: 80  0  0  6  0  0  2  5  0  0  0  2  6  0  0  0   ................

  16:  2  7  0  0  0  2  8  0  0  0  2  9  0            ................

slot   7:

   0: 80  0  0  7  0  0  2  a  0  0  0  2  b  0  0  0   ................

  16:  2  c  0  0  0  2  d  0  0  0  2  e  0            ................

... ...

... ...

slot  54:

   0: 80  0  0 36  0  0  e  5  0  0  0  e  6  0  0  0   ...6............

  16:  e  7  0  0  0  e  8  0  0  0  e  9  0            ................

slot  55:

   0: 80  0  0 37  0  0  e  a  0  0  0  e  b  0  0  0   ...7............

  16:  e  c  0  0  0  e  d  0  0  0  e  e  0            ................

从 idx2 的第 1 个叶节点的内容中,可以看到该叶节点一共有 55 个索引项。每个索引项都有 1 个键 (key) 和多个值 (value)。例如:第 1 个索引项的键 (key) 为 0x1,多个值 (value) 分别为 0x101、0x102、0x103、0x104,这说明“第 1 个索引项”指向 4 个数据行,这 4 个数据行的 ROWID(数据行 ID)分别为 0x101、0x102、0x103、0x104;第 55 个索引项的键 (key) 为 0x37,多个值 (value) 分别为 0xe0a、0xe0b、0xe0c、0xe0d、0xe0e,这说明“第 55 个索引项”指向 5 个数据行,这 5 个数据行的 ROWID(数据行 ID)分别为 0xe0a、0xe0b、0xe0c、0xe0d、0xe0e。

idx2 的其它节点的内容请参看文件 idx2.out(文件 idx2.out 被包含在附件“Informix 索引结构 .zip”中)。

根据 idx2 的各节点的内容,可以得出 idx2 的结构如图 4 所示。

图 4. 图 4. 单列非唯一索引 idx2 的结构

单列非唯一索引 idx2 的结构

多列唯一索引的结构

多列唯一索引和单列唯一索引在内部结构上的区别主要是:在多列唯一索引的节点中,索引项的键 (key) 由多个数据列构成;在单列唯一索引的节点中,索引项的键 (key) 由 1 个数据列构成。

下面以“多列唯一索引 idx3 的第 1 个叶节点”为例来说明多列唯一索引的节点。

idx3 的第 1 个叶节点的内容如下(获取“idx3 的第 1 个叶节点的内容”的过程与获取“idx1 的第 1 个叶节点的内容”的过程相似):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

addr             stamp    chksum nslots flag type         frptr frcnt next     prev

10:5377          110574370 28be   106    890  BTREE        1402  218   4        0      

    slot ptr   len   flg

    1    24    13    0 

    2    37    13    0 

    3    50    13    0 

    4    63    13    0 

    5    76    13    0 

    6    89    13    0 

    7    102   13    0 

    ... ...

    ... ...

    105  1376  13    0 

    106  1389  13    0 

slot   1:

   0: 80  0  0  1 80  0  0  1  0  0  1  1  0            ................

slot   2:

   0: 80  0  0  1 80  0  0  2  0  0  1  2  0            ................

slot   3:

   0: 80  0  0  1 80  0  0  3  0  0  1  3  0            ................

slot   4:

   0: 80  0  0  1 80  0  0  4  0  0  1  4  0            ................

slot   5:

   0: 80  0  0  1 80  0  0  5  0  0  1  5  0            ................

slot   6:

   0: 80  0  0  1 80  0  0  6  0  0  1  6  0            ................

slot   7:

   0: 80  0  0  1 80  0  0  7  0  0  1  7  0            ................

... ...

... ...

slot 105:

   0: 80  0  0  3 80  0  0  5  0  0  6  5  0            ................

slot 106:

   0: 80  0  0  3 80  0  0  6  0  0  6  6  0            ................

从 idx3 的第 1 个叶节点的内容中,可以看到该叶节点一共有 106 个索引项。每个索引项都有 1 个键 (key) 和 1 个值 (value),索引项的键由两个数据列构成。例如:第 1 个索引项的键 (key) 为(0x1,0x1),值 (value) 为 0x101;第 106 个索引项的键 (key) 为(0x3,0x6),值 (value) 为 0x606。

idx3 的其它节点的内容请参看文件 idx3.out(文件 idx3.out 被包含在附件“Informix 索引结构 .zip”中)。

根据 idx3 的各节点的内容,可以得出 idx3 的结构如图 5 所示。

图 5. 图 5. 多列唯一索引 idx3 的结构

多列唯一索引 idx3 的结构

3 种 Informix 索引在内部结构上的特点

从前面的叙述中,可以知道 3 种 Informix 索引在内部结构上的特点如表 2 所示。

表 2. 表 2. 3 种 Informix 索引在内部结构上的特点

索引种类 特点
单列唯一索引 在节点中,索引项的键 (key) 由 1 个数据列构成 ;
在节点中,每个索引项有 1 个值 (value)。
单列非唯一索引 在节点中,索引项的键 (key) 由 1 个数据列构成;
在非叶节点中,每个索引项有 1 个值 (value);
在叶节点中,每个索引项有 1 个或多个值 (value)。
多列唯一索引 在节点中,索引项的键 (key) 由多个数据列构成;
在节点中,每个索引项有 1 个值 (value)。

一些说明

下面是对本文的一些说明:

  1. 在本文叙述的索引中,索引项都是不跨页的。索引项跨页(即索引项 E 的一部分在页 P1,索引项 E 的另一部分在页 P2 上)的情况较少,也较复杂,不在本文的叙述范围内。
  2. 多列非唯一索引兼具“多列”和“非唯一”的特点:在节点中,索引项的键 (key) 由多个数据列构成;在非叶节点中,每个索引项有 1 个值 (value); 在叶节点中,每个索引项有 1 个或多个值 (value)。由于篇幅限制,本文不对“多列非唯一索引”进行详细叙述。
  3. 1 个索引在物理存储上可以由 1 个或多个 extent 组成。extent 的个数不影响索引的逻辑结构。为使叙述更加简明,本文叙述的每个示例索引在物理存储上都由 1 个 extent 组成。
  4. 在一般的索引中,1 个索引只有 1 个根节点。在 Informix 11.70 中新推出的 Forest-Of-Trees 类型的索引中,1 个索引可以有多个根节点。
  5. 在一般的索引中,Informix 使用 B+ 树作为索引的内部结构。在一些特殊的索引中,Informix 可能使用其它数据结构作为索引的内部结构。例如在处理空间数据 (spatial data) 时,Informix 使用了 R-Tree 作为索引的内部结构。这些特殊的索引结构不在本文的叙述范围内。

结束语

本文叙述了 3 种 Informix 索引的内部结构,使读者对 Informix 索引的层次、根节点、分支节点、叶节点等有较深的理解。

读者理解 Informix 索引的内部结构后,可以更好的设计 Informix 索引,较大的提升 Informix 数据库和 Informix 应用程序的性能。

转自https://www.ibm.com/developerworks/cn/data/library/techarticle/dm-1208xiey/

猜你喜欢

转载自blog.csdn.net/yq272393925/article/details/89150067