MySQL again with you from start to finish stroke index structure (2)

Foreword

Hello I go again, the end of the fast, as an aspiring farmer yard, I want to save myself a year-end summary. The database simply the most central and most difficult to get to know the content that is indexed to others.

For this blog I will talk about my own views index structures, and how to share one level up from scratch finally understood the index structure, connected to the text book.

Multi-page mode

In a multi-page mode, MySQL can finally complete the storage of multiple data, that is, by way of opening up a new page, the pieces of data on a different page, and then uses the same data structure linked list, connect each page. I can think fourth question: whether the query efficiency influential multi-page situation?

Impact of multi-page mode for the query efficiency

To address this issue, since it came out and asked, the answer is yes, some impact will have a multi-page query efficiency, the impact is mainly reflected in, by its very nature is also a multi-page list structure, as long as the list structure, query efficiency must not It will be high.

Assuming that a number of data and very, very large database will open up a new page, a new page will connect these together like linked lists, like, when we want to query certain pieces of data in so many pages, it will still head node traversal to exist on the page piece of data we're looking for exists, we finally optimized page catalog search efficiency in the data page, and now there's a page unit list, this is not wasted yet?

How to optimize multi-page mode

Since the multi-page mode will affect the efficiency of the query, then certainly you need a way to optimize queries in a multi-page mode. I believe some students already guessed, since we can use to optimize the page directory data area in the page, then we can take a similar approach to optimize this case multiple pages.

Yes, on-page and multi-page mode data areas are essentially linked lists, then indeed the same way to optimize it, it is the contents page.

So we compare page within the data area, to analyze how to optimize multi-page structure. When a single page, we adopted the directory page directory entries to point to a row of data, this data is that there is minimal data in the directory entry, then you can find the data page directory.

So for a multi-page structure can also be used in this way, the use of a directory entry to point to a page directory entry and the index value stored in the minimum data is stored in this page. And page directory different places that the level of this directory is managed by page, and the page directory management level is OK.

So the analysis here, the structure of our multi-page mode would be such as shown below:

There is a directory page to manage catalog page, that page is pointed to data stored in the directory page smallest data.

One thing to note here is: In fact, the nature of the contents page is page, general page data is stored project data and directory data is stored in the page address common page.

Suppose we want to find the data id = 19, then follow previous search methods, we need to look from the first page and found that it does not exist then the second page of search, has been found on the fourth page to find data id = 19 However, if you have a directory page id = 19 can be used compared with data stored in the page directory, a data larger than any found 19, then directed into the page id = 16 to find, and then directly in the page by page directory find the row-level data, you will soon be able to find 19 of the id data. As more and more data, the efficiency of this structure relative to the normal multi-page mode, the advantages will become increasingly apparent.

Return to the topic, I believe there is a better understanding of MySQL students have been found, the final painting this picture of us, it is a kind of index structure in MySQL --B + tree.

Introducing the B + tree

We will draw our existence contents page of multi-page schematic diagram of the macro, this may form the following chart:

This is what we going around in circles a B + tree from simple to complex formation. And conventional B + tree is slightly different, this is a B + tree on the meaning of MySQL, MySQL an index structure, in which each node can be understood as a page, and the page data is the leaf node, except leaf nodes other than the node is the directory page.

This can also be seen in the figures come out, the non-leaf nodes store only the index and leaf nodes only store the actual data, which is consistent with the characteristics of the B + tree.

Advantages of B + tree

  • Since all the data stored on the leaf nodes, and linked with a pointer, each leaf node is logically connected, so to find more friendly for the range.

  • B + trees are all of the data in the leaf node, so the B + tree query efficiency and stability, inquiries are generally three times.

  • B + tree in favor of scanning the database.

  • B+树有利于磁盘的IO,因为他的层高基本不会因为数据扩大而增高(三层树结构大概可以存放两千万数据量。

页的完整结构

说完了页的概念和页是如何一步一步地组合称为B+树的结构之后,相信大家对于页都有了一个比较清楚的认知,所以这里就要开始说说官方概念了,基于我们上文所说的,给出一个完整的页结构,也算是对上文中自己理解页结构的一种补充。

上图为 Page 数据结构,File Header 字段用于记录 Page 的头信息,其中比较重要的是 FIL_PAGE_PREV 和 FIL_PAGE_NEXT 字段,通过这两个字段,我们可以找到该页的上一页和下一页,实际上所有页通过两个字段可以形成一条双向链表。

Page Header 字段用于记录 Page 的状态信息。接下来的 Infimum 和 Supremum 是两个伪行记录,Infimum(下确界)记录比该页中任何主键值都要小的值,Supremum (上确界)记录比该页中任何主键值都要大的值,这个伪记录分别构成了页中记录的边界。

 

User Records 中存放的是实际的数据行记录,具体的行记录结构将在本文的第二节中详细介绍。Free Space 中存放的是空闲空间,被删除的行记录会被记录成空闲空间。Page Directory 记录着与二叉查找相关的信息。File Trailer 存储用于检测数据完整性的校验和等数据。

引用来源:https://www.cnblogs.com/bdsir/p/8745553.html

基于B+树聊聊MySQL的其它知识点

看到这里,我们已经了解了MySQL从单条数据开始,到通过页来减少磁盘IO次数,并且在页中实现了页目录来优化页中的查询效率,然后使用多页模式来存储大量的数据,最终使用目录页来实现多页模式的查询效率并形成我们口中的索引结构——B+树。既然说到这里了,那我们就来聊聊MySQL的其他知识点。

聚簇索引和非聚簇索引

所谓聚簇索引,就是将索引和数据放到一起,找到索引也就找到了数据,我们刚才看到的B+树索引就是一种聚簇索引,而非聚簇索引就是将数据和索引分开,查找时需要先查找到索引,然后通过索引回表找到相应的数据。InnoDB有且只有一个聚簇索引,而MyISAM中都是非聚簇索引。

联合索引的最左前缀匹配原则

在MySQL数据库中不仅可以对某一列建立索引,还可以对多列建立一个联合索引,而联合索引存在一个最左前缀匹配原则的概念,如果基于B+树来理解这个最左前缀匹配原则,相对来说就会容易很很多了。

首先我们基于文首的这张表建立一个联合索引:

create index idx_obj on user(age asc,height asc,weight asc)

我们已经了解了索引的数据结构是一颗B+树,也了解了B+树优化查询效率的其中一个因素就是对数据进行了排序,那么我们在创建idx_obj这个索引的时候,也就相当于创建了一颗B+树索引,而这个索引就是依据联合索引的成员来进行排序,这里是age,height,weight。

看过我之前那篇博客的同学知道,InnoDB中只要有主键被定义,那么主键列被作为一个聚簇索引,而其它索引都将被作为非聚簇索引,所以自然而然的,这个索引就会是一个非聚簇索引。

所以根据这些我们可以得出结论:

  • idx_obj这个索引会根据age,height,weight进行排序

  • idx_obj这个索引是一个非聚簇索引,查询时需要回表

根据这两个结论,首先需要了解的就是,如何排序?

单列排序很简单,比大小嘛,谁都会,但是多列排序是基于什么原则的呢(重点)?

实际上在MySQL中,联合索引的排序有这么一个原则,从左往右依次比较大小,就拿刚才建立的索引举例子,他会先去比较age的大小,如果age的大小相同,那么比较height的大小,如果height也无法比较大小, 那么就比较weight的大小,最终对这个索引进行排序。

那么根据这个排序我们也可以画出一个B+树,这里就不像上文画的那么详细了,简化一下:

数据:

B+树:

注意:此时由于是非聚簇索引,所以叶子节点不在有数据,而是存了一个主键索引,最终会通过主键索引来回表查询数据。

B+树的结构有了,就可以通过这个来理解最左前缀匹配原则了。

我们先写一个查询语句

SELECT * FROM user WHERE age=1 and height = 2 and weight = 7

毋庸置疑,这条语句一定会走idx_obj这个索引。

那么我们再看一个语句:

SELECT * FROM user WHERE height=2 and weight = 7

思考一下,这条SQL会走索引吗?

答案是否定的,那么我们分析的方向就是,为什么这条语句不会走索引。

上文中我们提到了一个多列的排序原则,是从左到右进行比较然后排序的,而我们的idx_obj这个索引从左到右依次是age,height,weight,所以当我们使用height和weight来作为查询条件时,由于age的缺失,那么就无法从age来进行比较了。

看到这里可能有小伙伴会有疑问,那如果直接用height和weight来进行比较不可以吗?显然是不可以的,可以举个例子,我们把缺失的这一列写作一个问号,那么这条语句的查询条件就变成了?27,那么我们从这课B+树的根节点开始,根节点上有127和365,那么以height和weight来进行比较的话,走的一定是127这一边,但是如果缺失的列数字是大于3的呢?比如427,527,627,那么如果走索引来查询数据,将会丢失数据,错误查询。所以这种情况下是绝对不会走索引进行查询的。这就是最左前缀匹配原则的成因。

  1.  最左前缀匹配原则,MySQL会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如 a=3 and b=4 and c>5 and d=6,如果建立(a,b,c,d)顺序的索引,d是无法使用索引的,如果建立(a,b,d,c)的索引则都可以使用到,a、b、d的顺序可以任意调整。 
  2.     =和in可以乱序,比如 a=1 and b=2 and c=3 建立(a,b,c)索引可以任意顺序,MySQL的查询优化器会帮你优化成索引可以识别的形式。

根据我们了解的可以得出结论:

只要无法进行排序比较大小的,就无法走联合索引。

可以再看几个语句:

SELECT * FROM user WHERE age=1 and height = 2

这条语句是可以走idx_obj索引的,因为它可以通过比较 (12?<365)。

SELECT * FROM user WHERE age=1 and weight=7

这条语句也是可以走ind_obj索引的,因为它也可以通过比较(1?7<365),走左子树,但是实际上weight并没有用到索引,因为根据最左匹配原则,如果有两页的age都等于1,那么会去比较height,但是height在这里并不作为查询条件,所以MySQL会将这两页全都加载到内存中进行最后的weight字段的比较,进行扫描查询。

SELECT * FROM user where age>1

这条语句不会走索引,但是可以走索引。这句话是什么意思呢?这条SQL很特殊,由于其存在可以比较的索引,所以它走索引也可以查询出结果,但是由于这种情况是范围查询并且是全字段查询,如果走索引,还需要进行回表,MySQL查询优化器就会认为走索引的效率比全表扫描还要低,所以MySQL会去优化它,让他直接进行全表扫描。

SELECT * FROM user WEHRE age=1 and height>2 and weight=7

这条语句是可以走索引的,因为它可以通过age进行比较,但是weight不会用到索引,因为height是范围查找,与第二条语句类似,如果有两页的height都大于2,那么MySQL会将两页的数据都加载进内存,然后再来通过weight匹配正确的数据。

为什么InnoDB只有一个聚簇索引,而不将所有索引都使用聚簇索引?

因为聚簇索引是将索引和数据都存放在叶子节点中,如果所有的索引都用聚簇索引,则每一个索引都将保存一份数据,会造成数据的冗余,在数据量很大的情况下,这种数据冗余是很消耗资源的。

补充两个关于索引的点

这两个点也是上次写关于索引的博客时漏下的,这里补上。

1.什么情况下会发生明明创建了索引,但是执行的时候并没有通过索引呢?

科普时间:查询优化器 一条SQL语句的查询,可以有不同的执行方案,至于最终选择哪种方案,需要通过优化器进行选择,选择执行成本最低的方案。

在一条单表查询语句真正执行之前,MySQL的查询优化器会找出执行该语句所有可能使用的方案,对比之后找出成本最低的方案。这个成本最低的方案就是所谓的执行计划。

优化过程大致如下:

1、根据搜索条件,找出所有可能使用的索引
2、计算全表扫描的代价
3、计算使用不同索引执行查询的代价
4、对比各种执行方案的代价,找出成本最低的那一个 。

参考:https://juejin.im/post/5d23ef4ce51d45572c0600bc

根据我们刚才的那张表的非聚簇索引,这条语句就是由于查询优化器的作用,造成没有走索引:

SELECT * FROM user where age>1

2.在稀疏索引情况下通常需要通过叶子节点的指针回表查询数据,什么情况下不需要回表?

科普时间:覆盖索引 覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。

当一条查询语句符合覆盖索引条件时,MySQL只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少I/O提高效率。

如,表covering_index_sample中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过SQL语句:select key2 from covering_index_sample where key1 = 'keytest';的时候,就可以通过覆盖索引查询,无需回表。

参考:https://juejin.im/post/5d23ef4ce51d45572c0600bc

例如:

SELECT age FROM user where age = 1

这句话就不需要进行回表查询。

结语

本篇文章着重聊了一下关于MySQL的索引结构,从零开始慢慢构建了一个B+树索引,并且根据这个过程谈了B+树是如何一步一步去优化查询效率的。

简单地归纳一下就是:

排序:优化查询的根本,插入时进行排序实际上就是为了优化查询的效率。
页:用于减少IO次数,还可以利用程序局部性原理,来稍微提高查询效率。
页目录:用于规避链表的软肋,避免在查询时进行链表的扫描。
多页:数据量增加的情况下开辟新页来保存数据。
目录页:“特殊的页目录”,其中保存的数据是页的地址。查询时可以通过目录页快速定位到页,避免多页的扫描。

 

END

 

Guess you like

Origin www.cnblogs.com/zydj333/p/12031716.html