mysql查询索引高度_查看InnoDB表每个索引的高度?

我们知道InnoDB表是索引组织表,分为聚集索引和二级索引,但不管哪种索引,其结构都是B+树结构。由于InnoDB B+树结构高扇区特性,所以每个索引高度基本在3-4层之间,如果数据量比较大,页比较小,如4K,那么高度也是可能破4的。问题来了,以上说法都是我们根据理论知识计算得出的结果,那么在InnoDB中如何查看每个索引的高度呢?InnoDB也没有提供相应的视图进行查看。然,只要明白InnoDB索引的内部构造,就能迅速得出索引的高度。

姜总这篇文章给出了一个方法,如下图InnoDB索引的内部构造:

mysql查询索引高度_查看InnoDB表每个索引的高度?_第1张图片

InnoDB是索引组织表,每个页都包含一个PAGE_LEVEL的信息(见上图右半部分),用于表示当前页所在索引中的高度。默认叶子节点的高度为0,那么root页的PAGE_LEVEL + 1就是这棵索引的高度。接下去的问题就是怎样得到一张表所有索引的Root页所在的位置呢?其实InnoDB中Root页默认就在3号页,且Root页的位置通常是不会更改的,为什么是3号页呢?因为0,1,2号的Page被类型为“FSP_HDR”、“IBUF_BITMAP”、“INODE”分别占用了,从3号Page开始才是存放数据和索引的页(Index)。

其实官方提供了内部视图来查看每个索引的Root页,通过下面的SQL语句可以查出某这表对应索引的Root页:

SELECT b.name,

a.name,

index_id,

TYPE,

a.space,

a.PAGE_NO

FROM information_schema.INNODB_SYS_INDEXES a,

information_schema.INNODB_SYS_TABLES b

WHERE a.table_id = b.table_id

AND a.space <> 0;

1

2

3

4

5

6

7

8

9

10

SELECTb.name,

a.name,

index_id,

TYPE,

a.space,

a.PAGE_NO

FROMinformation_schema.INNODB_SYS_INDEXESa,

information_schema.INNODB_SYS_TABLESb

WHEREa.table_id=b.table_id

ANDa.space<>0;

运行上述的SQL语句应该可以得到类似如下的结果(space等于0的为系统表):

+----------------+---------+----------+------+-------+---------+

| name | name | index_id | TYPE | space | PAGE_NO |

+----------------+---------+----------+------+-------+---------+

| sbtest/sbtest1 | PRIMARY | 319 | 3 | 138 | 3 |

| sbtest/sbtest1 | idx_k_c | 320 | 0 | 138 | 4 |

+----------------+---------+----------+------+-------+---------+

2 rows in set (0.00 sec)

1

2

3

4

5

6

7

+----------------+---------+----------+------+-------+---------+

|name|name|index_id|TYPE|space|PAGE_NO|

+----------------+---------+----------+------+-------+---------+

|sbtest/sbtest1|PRIMARY|319|3|138|3|

|sbtest/sbtest1|idx_k_c|320|0|138|4|

+----------------+---------+----------+------+-------+---------+

2rowsinset(0.00sec)

其中(SPACE,PAGE_NO)就是索引的Root页。SPACE对应每个表空间ID号,PAGE_NO对应每个页的ID号。

有了这些信息就可以方便的定位啦,因为PAGE_LEVEL在每个页的偏移量64位置初,占用两个字节,通过hexdump这样的工具就可以快速定位到所需要的树高度信息:

$ hexdump -s 49216 -n 02 /var/lib/mysql/sbtest/sbtest1.ibd

000c040 0200

1

2

$hexdump-s49216-n02/var/lib/mysql/sbtest/sbtest1.ibd

000c0400200

查看sbtest1表,49216表示的是3*16384+64(这里innodb_page_size设置为了16384,如果是8192就是3*8192),即第3个页偏移量64位置开始读取2个字节,这里PAGE_LEVEL为00 02,那么索引的高度就为3。

最后,如果我们不知道索引内部结构,那么就可以使用工具来协助,innodb_ruby是一个非常好的各种维度查看索引及页结构的工具。所以,同样使用innodb_ruby查出每个表的索引信息。

$ innodb_space -s ibdata1 -T sbtest/sbtest1 space-indexes

id name root fseg used allocated fill_factor

319 PRIMARY 3 internal 36 96 37.50%

319 PRIMARY 3 leaf 41094 41120 99.94%

320 idx_k_c 4 internal 521 608 85.69%

320 idx_k_c 4 leaf 36159 41376 87.39%

1

2

3

4

5

6

$innodb_space-sibdata1-Tsbtest/sbtest1space-indexes

idnamerootfsegusedallocatedfill_factor

319PRIMARY3internal369637.50%

319PRIMARY3leaf410944112099.94%

320idx_k_c4internal52160885.69%

320idx_k_c4leaf361594137687.39%

id:表示此索引的ID。

name:索引的名称,PRIMARY代表的就是聚集索引,因为InnoDB表是聚集索引组织表,行记录就是聚集索引;idx_c就是辅助索引的名称。

root:索引中根节点的page号,可以看出聚集索引的Root节点是第3号page(前0、1、2号Page已经被使用),辅助索引的根节点是第4个page。

fseg:page的说明,internal表示非叶子节点或属于根节点,leaf表示叶子节点(也就是数据页)。

used:索引使用了多少个page,可以看出聚集索引的非叶子节点使用了36个page,叶子节点使用了41094个page;辅助索引的非叶子节点使用了521个页,叶子节点使用了36159个page。

allocated:索引分配了多少个page,可以看出聚集索引的非叶子节点分配了96个page,叶子节点分配了41120个page;辅助索引的非叶子节点分配了608个页,叶子节点分配了41376个page。

fill_factor:索引的填充度,used/allocated表示填充度,也就是实际使用的大小百分比。

同样,现在我们知道了Root节点页后,就可以使用innodb_ruby的另外一个功能,打印页结构信息,需要了解InnoDB页结构。

$ innodb_space -s ibdata1 -T sbtest/sbtest1 -p 3 page-dump

fil header:

{:checksum=>900405545,

:offset=>3,

:prev=>nil,

:next=>nil,

:lsn=>20030130167,

:type=>:INDEX,

:flush_lsn=>0,

:space_id=>138}

fil trailer:

{:checksum=>3300141601, :lsn_low32=>2850260983}

page header:

{:n_dir_slots=>9,

:heap_top=>575,

:garbage_offset=>0,

:garbage_size=>0,

:last_insert_offset=>567,

:direction=>:right,

:n_direction=>34,

:n_recs=>35,

:max_trx_id=>0,

:level=>2,

:index_id=>319,

:n_heap=>37,

:format=>:compact}

fseg header:

{:leaf=>

<:inode space=", fseg=2>,

:internal=>

<:inode space=", fseg=1>}

sizes:

header 120

trailer 8

directory 18

free 15783

used 601

record 455

per record 13.00

page directory:

[99, 164, 216, 268, 320, 372, 424, 476, 112]

system records:

.............................

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

47

48

49

$innodb_space-sibdata1-Tsbtest/sbtest1-p3page-dump

filheader:

{:checksum=>900405545,

:offset=>3,

:prev=>nil,

:next=>nil,

:lsn=>20030130167,

:type=>:INDEX,

:flush_lsn=>0,

:space_id=>138}

filtrailer:

{:checksum=>3300141601,:lsn_low32=>2850260983}

pageheader:

{:n_dir_slots=>9,

:heap_top=>575,

:garbage_offset=>0,

:garbage_size=>0,

:last_insert_offset=>567,

:direction=>:right,

:n_direction=>34,

:n_recs=>35,

:max_trx_id=>0,

:level=>2,

:index_id=>319,

:n_heap=>37,

:format=>:compact}

fsegheader:

{:leaf=>

<:inodespace>,fseg=2>,

:internal=>

<:inodespace>,fseg=1>}

sizes:

header120

trailer8

directory18

free15783

used601

record455

perrecord13.00

pagedirectory:

[99,164,216,268,320,372,424,476,112]

systemrecords:

.............................

页结构信息中有一个level字段,表示的就是Root节点页的高度,同样,level + 1就等于这个索引的高度。

如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。

你可能感兴趣的:(mysql查询索引高度)