zoukankan      html  css  js  c++  java
  • B-Tree

    1.  B-Tree索引

    1.1.  索引类型

    Postgresql的B-Tree索引页分为4种类别

    l  meta page

    存放的是索引的元数据信息(描述索引本身的信息),每个索引文件的第0页都是meta page

    l  root page

    meta page的下一页(第一页)叫做root page,对于索引量小的情况(一页root page即可存放所有索引数据),只有一个root page即可

    l  branch page

    用于连接root page和leaf page(不存放实际的数据,存放索引数据)

    l  leaf page

    存放指向tuple物理位置的索引

     

    1.2.  bt_metap函数

    l  简述

    返回有关B树索引的元页面的信息,param1:索引名

    l  字段

           magic:

           version:版本号

           root:root页的页号(对应bt_page_stats.blkno)

           level:branch page和leaf page的层数之和。表示索引的层数,level为0表示只有root page。level=1表示有一个root page和多个leaf page

           fastroot:

           fastlevel:

    1.3.  bt_page_stats函数

    l  简述

    返回有关B树索引的单个页面的信息,param1:索引名,param2:第几页索引(第0页存放的是meta page,不能用这个函数查看)

    l  字段

           blkno:block no,即索引文件的页号

           type:索引类型

           live_items:对于leaf page表示有效索引的数量,对于root/branch page表示子索引页的数量

           dead_items:无效索引的数量,或者是无效子索引页

           avg_item_size:平均字段大小

           page_size:文件页的大小

           free_size:空闲的大小

           btpo_prev:指向同一级的当前索引页的上一页(同一级索引是双向链表)

           btpo_next: 指向同一级的下一个索引页,如果没有上一页或者下一页则指向meta page

           btpo:索引的层级,0表示最低级(leaf page,存放的是指向物理位置的指针)

           btpo_flags:指示索引页的类型,0==branch page,1==leaf page,2==root page, 3==root page & leaf page

    1.4.  bt_page_items函数

    l  简述

    返回B树索引页上所有entry(行)的详细信息,param1:索引名,param2:页号

    l  字段      

    itemoffset:

           ctid:如果btpo==0(leaf page),则值指向tuple的物理位置,可以使用类似select * from tab1 where ctid='(0,1)';进行查询。否则为子索引页的页号(忽略后一项),如(3,1)表示blkno=3的页为子索引页

           itemlen:

           data:

                  leaf page存放的是索引数据的值(非最右页的第一项存放的是下一索引页的最小值,最右页第一项存放的是tuple数据),

                  root page存放的是子索引页的最小值(第一项为空,因为最左页不存放最小值),

                  branch page非最右页第一项存放的是下一个索引页的最小值,第二项为空,

                  最右页第一项为空(因为没有下一个索引页),第二项指向第一个子索引页的最小值

    1.5.  实战1-0级索引(max:407条)

    l  sql命令

    drop table if exists tab1;

    create table tab1(id int primary key, info text);

    insert into tab1 select generate_series(1,407), md5(random()::text);

    select * from bt_metap('tab1_pkey');

    select * from bt_page_stats('tab1_pkey',1);

    select * from bt_page_items('tab1_pkey',1) limit 3;

    select count(*) from bt_page_items('tab1_pkey',1);

    insert into tab1 select 408, md5(random()::text);

    select * from bt_metap('tab1_pkey');

    l  分析

           插入407条数据,通过bt_metap函数查看主键索引(默认为btree索引),显示索引级别为0级,root页的页号为1.(当前页为meta page,是第0页,固定值)

           通过bt_page_stats查看root页的统计信息,live_items表示其索引了407条数据(这里因为没有子索引页),btpo=0表示这是最底层的页,btpo_flags=3表示为root页和leaf页。

           通过bt_page_items查看root页的数据内容,data为索引的值。

           通过count可以看出,root页的确有407条数据,每个索引项一条数据。

           再插入一条数据,查看索引级别变为了1,说明产生了leaf page。具体待1级索引实战说明。

    l  索引结构分析

    首先说结论,一个索引页最多存放407条int索引数据。

    已知页头占用24字节,每个索引项的指针占用4字节(存放在head后面),索引数据(从末尾开始存放)占用16字节(可以通过下图的itemlen得出,data实际是int 4字节,填充了4字节,另外8字节目前分析应该是ctid,待确定),另通过page_header可以看出预留了16字节。所以,计算公式如下(实测亦如此,此处略图):

           8192-24-16=8152

           8152 / (16+4) = 407            (可以存放407项)

           8152 % (16+4) = 12        (页的空闲空间为12)

    l  执行结果

     

    l  理论图解

          

    1.6.  实战-1级索引(max:149369条)

    l  sql命令

           drop table if exists tab1;

    create table tab1(id int primary key, info text);

    insert into tab1 select generate_series(1,1000), md5(random()::text);

    select * from bt_metap('tab1_pkey');

    select * from bt_page_stats('tab1_pkey',1);

    select * from bt_page_stats('tab1_pkey',2);

    select * from bt_page_stats('tab1_pkey',3);

    select * from bt_page_stats('tab1_pkey',4);

    select * from bt_page_items('tab1_pkey',1);

    select * from bt_page_items('tab1_pkey',2);

    select * from bt_page_items('tab1_pkey',3);

    select * from bt_page_items('tab1_pkey',4);

    l  分析

    向表中插入1000条数据

    通过bt_metap可以看出索引级别为1,root页的页号为3.

    通过bt_page_stats的live_items=3可以看出root页有三个子索引页(此时root本身不在存放索引内容),通过btpo_flags=2也可以看出是root页,btpo=1表示其内存储的不是指向底层数据的指针。

    通过bt_page_stats可以看出页1,2,4分别有367,367,268条数据。367+367+268=1002(多了两条??).

    通过btpo_prev和btpo_next可以看出一级索引之间的双向连接关系如下图:

     

           通过bt_page_items可以看出root页有3个子索引页(图上失误,使用了limit3,实际也只有三条结果)。子索引页的页号可以由ctid得到(1,1),(2,1),(4,1),可知子页页号为1,2,4(对于非叶子索引,忽略ctid的后一个字段)。data项存放的是子索引页的最小值,第一项(1号页)为空,因为最左页不保存最小值。第二页的最小值为016f=367,第四页的最小值为02dd=733=366+366+1(366为上面的live_items-1,见下面说明)。

           通过bt_page_items可以看出leaf 页1的第一项存放的是页2的最小值016f,页2的第一项存放的是页4的最小值,页4的第一项存放的是正常的数据(因为没有下一页)。

    所以,验证上面一个问题,总数据数量367+367+268=1002,因为前两页,分别有一条数据用来保存下一页的最小值。

    l  执行结果

          

      

      

    l  理论图解

                 

    1.7.  实战-2级索引(max:4200w左右)

    l  sql命令

    drop table if exists tab2;

    create table tab2(id int primary key);

    insert into tab2 select generate_series(1,4200*10000);

    select * from bt_metap('tab2_pkey');

    select * from bt_page_stats('tab2_pkey',412);

    select * from bt_page_stats('tab2_pkey',3);

    select * from bt_page_items('tab2_pkey',412);

    select * from bt_page_items('tab2_pkey',3);

    select * from bt_page_items('tab2_pkey',411);

    select * from bt_page_items('tab2_pkey',115098);

    select * from bt_page_items('tab2_pkey',1);

    select * from bt_page_items('tab2_pkey',2);

    select * from bt_page_items('tab2_pkey',574);

    select * from bt_page_items('tab2_pkey',287);

    l  分析

    省略

    l  执行结果

    省略

    l  理论图解

       

    参考文档:

      https://github.com/digoal/blog/blob/master/201605/20160528_01.md?spm=a2c4e.11153940.blogcont111793.15.50575bf0hMnvm4&file=20160528_01.md

      https://yq.aliyun.com/articles/111793

  • 相关阅读:
    L347
    2019.4.22 英语阅读
    L345 大脑复生
    L343 中译英
    L342 Air Pollution Is Doing More Than Just Slowly Killing Us
    Is It Always a Good Idea to Reach Outside Your Comfort Zone?
    2019.4月 商务英语场景
    元器件横截面-这里有很多专业词汇
    python 列表和元组 还有range
    python 基本数据类型简介intstr bool
  • 原文地址:https://www.cnblogs.com/gc65/p/11011916.html
Copyright © 2011-2022 走看看