MySQL의 연구는 결론을 내렸다

첫째, 얼굴 질문 : 이노 A B의 + 트리에서 얼마나 많은 데이터 행이 저장 될 수 있는가?

1, InnoDB는 B + 트리에는 얼마나 많은 데이터 행을 저장을 할 수있다?

  저장 얼마나 많은 데이터 행 InnoDB는 B + 트리에는 수있다? 이 질문에 대한 대답은 간단하다 : 약 20,000,000.

  왜 그렇게 많이는? 이 문제를 알아 내기 위해 밖으로 계산 될 수 있기 때문에, 우리는 InnoDB의 인덱스 데이터 구조, 데이터 구성의 시작과 함께 시작합니다.

  데이터를 저장할 때 우리 모두가 컴퓨터를 알고, 가장 작은 메모리 셀, 우리의 현금처럼 오늘 헤어입니다 순환의 최소 단위가있다. 컴퓨터 디스크 저장 유닛에 최소한의 데이터 인 섹터 , 섹터의 크기는 512 바이트, 파일 시스템 (예를 들어 XFS / EXT4) 그 블록의 최소 단위의 블록 크기는 4K이고 우리입니다 이노 스토리지 엔진은 자신의 최소 저장 단위가 - 페이지 (페이지), 페이지 크기는 16K입니다.

2, 다음은 몇 가지도 최소 저장 단위를 이해하는 데 도움이

  파일 크기 (1) 파일 시스템은 1.25KB을하지만, 4킬로바이트의 디스크 공간을 차지했다. 즉, 메모리 셀 블록의 파일 시스템의 최소 크기를 킬로바이트이다.

     

  (2) InnoDB는 모든 데이터 파일 (접미사 IBD 파일), 자신의 크기는 항상 16384 (16K) 정수 배이다.

     

  디스크 부문, 파일 시스템, InnoDB 스토리지 엔진은 자신의 최소 메모리 셀을 가지고있다.

 

  우리의 기본 MySQL의 InnoDB의 페이지 크기에 16K입니다 물론, 또한 매개 변수를 설정할 수 :

  SQL 문을 실행합니다 : 

  SHOW의 VARIABLES LIKE  ' innodb_page_size ' ;

   다음과 같은 결과를 반환 :

   

  데이터 테이블은 페이지에 저장되므로 페이지의 데이터 얼마나 많은 행을 저장할 수 있습니까? 다음 라인 (16)의 페이지는 데이터를 저장할 수있는 데이터의 행 1K의 크기하자.

  如果数据库只按这样的方式存储,那么如何查找数据就成为一个问题,因为我们不知道要查找的数据存在哪个页中,也不可能把所有的页遍历一遍,那样太慢了。所以人们想了一个办法,用B+树的方式组织这些数据。如图所示:

   

  在B+树中,首先将数据记录按主键进行排序,分别存放在不同的页中(这里一个页中只存放3条记录,实际情况可以存放很多),其中叶子节点的页存储的是数据表的行数据,而非叶子节点的页存放键值 + 指向孩子页的指针,如图中page number=3的页,该页存放键值和指向数据页的指针,这样的页由N个键值+指针组成。当然它也是排好序的。这样的数据组织形式,我们称为索引组织表。现在来看下,要查找一条数据,怎么查?

  如select * from user where id=5;

  这里id是主键,我们通过这棵B+树来查找,首先找到根页,你怎么知道user表的根页在哪呢?其实每张表的根页位置在表空间文件中是固定的,即page number=3的页(这点我们下文还会进一步证明),找到根页后通过二分查找法,定位到id=5的数据应该在指针P5指向的页中,那么进一步去page number=5的页中查找,同样通过二分查询法即可找到id=5的记录:

  | 5 | zhao2 | 27 |

  现在我们清楚了InnoDB中主键索引B+树是如何组织数据、查询数据的,我们总结一下:

    1、InnoDB存储引擎的最小存储单元是页,页可以用于存放数据也可以用于存放键值+指针,在B+树中叶子节点存放数据,非叶子节点存放键值+指针,每个页存放16KB的数据。

    2、索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中,进而在去数据页中查找到需要的数据;

3、那么回到我们开始的问题,通常一棵B+树可以存放多少行数据?

  这里我们先假设B+树高为2,即存在一个根非叶子节点和若干个叶子节点,根叶子节点存储的指针数即叶子节点数,那么这棵B+树的存放总记录数为:根节点指针数 * 单个叶子节点记录行数

  上文我们已经说明单个叶子节点(页)中的记录数=16K/1K=16。(这里假设一行记录的数据大小为1k,实际上现在很多互联网业务数据记录大小通常就是1K左右)。

  那么现在我们需要计算出非叶子节点能存放多少指针?

  其实这也很好算,我们假设主键ID为bigint类型,长度为8字节,而指针大小在InnoDB源码中设置为6字节,这样一共14字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即16384/14=1170,即一个非叶子节点能存放1170个指针。那么可以算出一棵高度为2的B+树,能存放1170*16=18720条这样的数据记录。

  根据同样的原理我们可以算出一个高度为3的B+树可以存放1170*1170*16=21902400条这样的记录。

  所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。

4、怎么得到InnoDB主键索引B+树的高度?

  上面我们通过推断得出B+树的高度通常是1-3,下面我们从另外一个侧面证明这个结论。在InnoDB的表空间文件中,约定page number为3的代表主键索引的根页,而在根页偏移量为64的地方存放了该B+树的page level。如果page level为1,树高为2,page level为2,则树高为3。即B+树的高度=page level+1;下面我们将从实际环境中尝试找到这个page level。

  在实际操作之前,你可以通过InnoDB元数据表确认主键索引根页的page number为3,你也可以从《InnoDB存储引擎》这本书中得到确认。

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;

  SQL执行结果如下:

  

  可以看出,所有的PRIMARY主键索引根页的PAGE_NO都是3,辅助索引的根页的PAGE_NO都是其他页。

  下面我们对数据库表空间文件做想相关的解析:

  

  因为主键索引B+树的根页在整个表空间文件中的第3个页开始,所以可以算出它在文件中的偏移量:16384*3=49152(16384为页大小)

  另外根据《InnoDB存储引擎》中描述在根页的64偏移量位置前2个字节,保存了page level的值,因此我们想要的page level的值在整个文件中的偏移量为:16384*3+64=49152+64=49216,前2个字节中。

  接下来我们用hexdump工具,查看表空间文件指定偏移量上的数据:

   

  linetem表的page level为2,B+树高度为page level+1=3;region表的page level为0,B+树高度为page level+1=1;customer表的page level为2,B+树高度为page level+1=3;

  这三张表的数据量如下:

   

5、小结

  lineitem表的数据行数为600多万,B+树高度为3,customer表数据行数只有15万,B+树高度也为3。可以看出尽管数据量差异较大,这两个表树的高度都是3,换句话说这两个表通过索引查询效率并没有太大差异,因为都只需要做3次IO。那么如果有一张表行数是一千万,那么他的B+树高度依旧是3,查询效率仍然不会相差太大。region表只有5行数据,当然他的B+树高度为1。

6、最后回顾一道面试题

  有一道MySQL的面试题,为什么MySQL的索引要使用B+树而不是其它树形结构?比如B树?

  现在这个问题的复杂版本可以参考本文;

  简单版本回答是:

  因为B树不管叶子节点还是非叶子节点,都会保存行数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出),指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低;

另外,关于MySQL的索引为什么要使用B+树的更多内容,可以参考:《为什么MySQL数据库索引选择使用B+树?

7、总结

  本文从一个问题出发,逐步介绍了InnoDB索引组织表的原理、查询方式,并结合已有知识,回答该问题,结合实践来证明。当然为了表述简单易懂,文中忽略了一些细枝末节,比如一个页中不可能所有空间都用于存放数据,它还会存放一些少量的其他字段比如page level,index number等等,另外还有页的填充因子也导致一个页不可能全部用于保存数据。关于二级索引数据存取方式可以参考MySQL相关书籍,他的要点是结合主键索引进行回表查询。

  参考资料:

    1、《MySQL技术内幕:InnoDB存储引擎》

    2、http://www.innomysql.com/查看-innodb表中每个的索引高度/

  原文地址:

    www.cnblogs.com/leefreeman/p/8315844.html

二、为什么MySQL数据库索引选择使用B+树?

  首先对常见的树进行介绍 

1、二叉查找树

(1)二叉树简介:

  二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质:

  1、任意节点左子树不为空,则左子树的值均小于根节点的值;

  2、任意节点右子树不为空,则右子树的值均大于于根节点的值;

  3、任意节点的左右子树也分别是二叉查找树;

  4、没有键值相等的节点; 

 

추천

출처www.cnblogs.com/aiqiqi/p/10952118.html