[Speaking] MySQL combat 45 index finishing section

This article excerpt from geek talk time [45] MySQL combat

Why should the index? What is the role of the index?

In fact, in order to improve the efficiency of data queries, just like the book directory as the index appears. A book by a certain knowledge we can point directory quickly locate them; for it is actually indexed database directory, you can quickly locate the index have a one or more records.

Common index model

Hash tables

A hash table is keyed - configuration values ​​(key-value) for storing data, we simply enter the value to be searched, i.e., key, can find the corresponding value, that value.

Structural features

The values ​​in the array, a hash function with a key to convert into a determined position, then this position value in the array. When the case of multiple key values ​​appear with a value after conversion hash function. This time will pull out a list for storage.

Case

Suppose now maintain a list of names and identity card information, look for the corresponding representation according to the name of the ID card, then hash index corresponding schematic diagram as follows

image.png

1 hash of intentions

FIG, User2 User4 and calculated values ​​are based on the ID number N, with behind it a linked list memory. If you want to find what is the name corresponding to User2, ID_card_n2 calculated first value of N by a hash function, and then traversed in order to find User2.

In four ID_card_n value here is not increasing, the benefits of doing so is to increase the time will soon be directly added back side; drawback is that the stored data is not ordered, so when doing a full table query interval scanning speed is very slow.

The hash table structure only applies to the equivalent queries.

Ordered array

Structural features

Will be stored into the data array, the data is sequentially stored in the array, from left to right in descending or ascending.

Case

In an example of the hash table, the results achieved using an ordered array as follows

image.png

2 a schematic view of an ordered array

这里假设身份证是没有重复的,这个数组是按照身份证的递增顺序保存的。这时候如果刷要查询 ID_card_n2 对应的姓名,用二分查找法可以快速定位到这条记录,同时如果要进行范围查询也是很快的,比如要查找身份证号在 [ID_card_X, ID_card_N] 区间的 User,可以先用二分查找法找到 ID_card_X 的值,如果没有则找到大于 ID_card_X 的第一个值,然后向右遍历,知道找到第一个大于 ID_card_N 的值退出循环。

但是往数组中插入一条记录的时候需要挪动后边所有的元素,这样的成本太高,同样的删除一条记录也会导致后边所有的元素往前挪动。

有序数组结构适用于等值和范围查询,但是插入和删除的效率太慢。

二叉搜索树

结构特点

二叉搜索树每个节点大于左儿子小于右儿子。

案例

上文例子,二叉搜索树实现如下

image.png
图 3 二叉搜索树示意图

如果我们要找到 ID_card_n2 的话,根据二叉搜索树的特点,按照图中的搜索顺序依次是:UserA→UserC→UserF→User2。

InnoDB索引模型

InnoDB 使用了 B+ 树索引模型,数据都是存储在 B+ 树中的,每一个索引都对应一棵 B+ 树。

B-Tree

image.png

B树 是一棵多路平衡树且有以下特点:

  1. m阶B树 表示该树每个节点最多有 m 个孩子;
  2. 除根节点和叶子节点外,其它每个节点至少有 ceil(m / 2) 个孩子;
  3. 若根节点不是叶子节点,则至少有两个孩子;
  4. 所有叶子节点都在同一层,叶子节点不包含任何关键字;
  5. 每个叶子节点包含 n 个关键字信息;
    • Ki(i = 1...n) 为关键字,且关键字按顺序升序排序 k(i-1)<Ki;
    • Pi 为指向子树根的节点,且指针 P(i-1) 指向子树中所有节点的关键字均小于 Ki,但都大于 K(i-1);
    • 关键字个数 n 必须满足: ceil(m / 2) - 1 <= n <= m-1

image.png

B+树作为数据库索引的优势

image.png

B+ Tree 是在 B-Tree 基础上的优化,使其更适合实现外存储索引结构,InnoDB引擎就是基于它实现索引结构,B+Tree 相对于 B-Tree 的优势:

  1. B+树的磁盘读取代价低:B+树 所有的内部节点没有关键字的具体信息(只存储了key的信息),这样可以使内部节点相对更小。一个硬盘块中包含的节点信息越多,一次性读取内存中的关键字也就越多,相对来说就是 IO 读写次数的降低,也可以说是每次 IO 操作的可观看数据也就越多;
  2. B+树便于执行扫库操作:B树在分支节点上都保存着数据,要找到具体的顺序数据,必须用中序遍历的方式按序扫库;由于B+树的数据都存储在叶子节点上,所有节点均为索引,所以 B+树 直接从叶子节点挨个扫一遍就完了;B+树 支持范围查询(rang-query)非常方便,而B树不支持;
  3. B+ 树查询效率更加稳定:由于 B+树 的数据都存储在叶子节点上,分支节点均为索引,所以对于任意关键字的查找都必须从根节点走到分支节点,所有关键字查询路径长度相同,每个数据的查询效率差不多。对于 B树 而言,分支节点也保存有数据,对于每一个数据的查询所走的路径长度也是不一样的,效率也就不一样;

B+Tree 与 B-Tree 的不同

  • 非叶子节点只存储键值信息
  • 所有叶子节点之间都有一个链指针
  • 数据记录都存放在叶子节点中

索引维护

image.png

B+树 为了维护索引的有序性,在插入新值的时候需要做必要的维护,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后插入一个新的将是。如果插入值的 ID 为400,需要逻辑上挪动后面的数据,空出位置。

如果 R5 所在的数据页已经满了,根据 B+树 的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去,这个过程称为页分裂。页分裂还会影响数据页的利用率,原本在一个页的数据,现在分到两个页中,整体的空间利用率降低大约 50%。

当相邻的两个页由于删除了数据,利用率很低之后,会将数据页做合并,合并的过程可以认为是分裂过程的逆过程。

关于索引重建

对于以下这两个重建索引的作法,说出你的理解。如果有不合适的,为什么,更好的方法是什么?

// 方案1
alter table T drop index k;
alter table T add index(k);
// 方案2
alter table T drop primary key;
alter table T add primary key(id);

为什么重建索引?

索引可能因为删除,或者页分裂等原因,导致数据页有空洞,重建索引的过程会创建一个新的索引,把数据按顺序插入,这样页面的利用率最高,也就是索引更紧凑、更省空间。

解答

重建主键的过程不合理:

  1. 不论是删除还是创建主键都会整个表重建
  2. 连续执行两个语句,相当于第一个语句白做
  3. 两个语句可以使用 alter table T engine=InnoDB 代替

索引类型

主键索引

主键索引叶子节点中存储的是整行数据,从物理结构的角度也叫 聚簇索引

非主键索引

  • 非主键索引的叶子节点存储的是主键的值,从物理存储的角度也叫 二级索引
  • 二级索引存储主键,是为了减少出现行移动或数据页分裂时二级索引的维护工作,但会让二级索引占用更多的空间。

基于主键索引和普通查询的查询的区别

  • 主键索引:只需要搜索主键这棵树。
  • 普通索引:先搜索普通索引对应的树得到ID,在根据ID在主键索引的树上找到对应的数据,这个过程称为回表。

聚簇索引的注意点有哪些?

聚簇索引最大限度的提高了 IO 密集型应用的性能,但它也有限制:

  1. 插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的,否则会出现页分裂,严重影响性能。所以一般 InnoDB 表,都会定义一个自增的id作为主键。

    面试问题:为什么主键需要自增ID,或者为什么主键需要带有时间行关联。

  2. 更新主键的代价很高,因为将会导致被更新的行移动。因此,InnoDB表一般主键不可更新。

    MySQL默认情况下,主键是允许更新的。MongoDB主键是不允许更新的。

  3. 二级索引访问需要回表。

    有种情况无需二次查找,就是索引覆盖。

  4. 主键ID建议使用整型。因为,每个主键索引的 B+Tree 节点的键值可以存储更多主键ID,每个非主键索引的 B+Tree 节点的数据可以存储更多的主键ID。

什么场景适合使用业务字段直接做主键?

  • 只有一个索引
  • 该索引必须有唯一索引
  • KV场景,由于没有其他索引,所以不用考虑其他索引的叶子节点大小的问题
  • 此时直接将这个索引设置为主键,可以避免回表

覆盖索引

如果执行的语句是 select ID from T where k between 3 and 5; ,这时只需要查 ID 的值,而ID的值已经在 k 索引树上了,因此可以直接拿到查询结果,不需要回表。也就是说索引 k 已经覆盖了我们的查询需求,我们称为覆盖索引

覆盖索引的优势

覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。

联合索引

业务例子

一个市民信息表上,是否有必要将身份证号 和 名字 建立联合索引?

如果有一个高配请求,要根据市民的身份照查询他的姓名,这个联合索引就很有意义了。它可以在这个高配请求上用到覆盖索引,不需要回表。

最左前缀原则

image.png

前提

现在有这么一个联合索引,(name,age)。

索引项是按照索引定义里面出现的字段顺序排序的,不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。

  • 这个最左前缀可以是联合索引的最左N个字段
  • 也可以是字符串索引的最左M个字符

例子

  • 查询条件 name='张三',可以快速定位到 ID4,然后向后遍历得到所有的结果集
  • 查询条件 name like '张%' 时,此时也可以用上索引,查找到 ID3,然后向后遍历得到所有结果集

建立索引时,如何安排索引内的字段排序?

  • 原则是,如果通过调整顺序,可以少维护一个索引,name这个顺序往往就是需要优先考虑采用的。
  • 如果既有联合索引,又有基于 a、b 各自的查询。查询条件里只有 b 的查询,是无法使用 (a, b) 这个联合索引的,此时就要同时维护 (a, b) ,(b) 这两个索引。
  • 考虑空间问题,比如市民表,name 字段比 age 字段大,建议创建一个 (name, age) 和一个 (age)

索引创建合理性例子

create table `geek` (
    `a` int(11) not null,
    `b` int(11) not null,
    `c` int(11) not null,
    `d` int(11) not null,
    primary key (`a`, `b`),
    key `c` (`c`),
    key `ca` (`c`, `a`),
    key `cb` (`c`, `b`),
) engine=InnoDB;

既然主键包含了a、b这两个字段,那意味着单独在字段c上创建一个索引,就已经包含三个字段了,为什么要创建“ca”、“cb”这两个索引?

同事告诉他,是因为他们的业务里面有这样的两种语句:

select * from geek where c=N order by a limit 1;select * from geek where c=N order by b limit 1;

问题,这位同事解释的对吗,为了这两个查询模式,这两个索引是否都是必须的?为什么?

  • 索引ca 的组织是先按c 排序,再按a 排序,同时记录主键,主键部分只有b,这个跟索引c的排序结果是一样的
  • 索引cb 的组织是先按c 排序,再按b 排序,同时记录主键,主键部分只有a
  • 所以,ca 可以去掉,cb 需要保留

索引下推

此处还是以市民表的联合索引 (name, age) 为例,需求为 检索出表中 名字第一个字是张,而且年龄是 10岁的所有男孩。

select * from tuser where name like '张%' and age=10 and ismale=1;

根据最左前缀原则,这个语句在搜索索引树的时候,只能用 “张”,找到一个满足条件的记录 ID3。然后判断其他条件是否满足条件。

在 MySQL5.6 之前,只能从 ID3 开始一个个的回表,到主键索引上找出数据行,在对比字段。

image.png

在 MyQL5.6 之后引入了索引下推优化(index condition pushdown),可以在索引遍历的过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,从而减少了回表的次数。

image.png

MyISAM索引实现

索引实现原理

MyISAM 引擎同 InnoDB 一样,都是使用 B+Tree 作为索引结构。差别在于:

  • InnoDB 的数据文件本身就是索引文件。MyISAM 索引文件和数据文件是分离开的,索引文件仅保存数据记录的地址。

主键索引和辅助索引

image.png

image.png

上图分别为主索引和辅助索引,由于 MyISAM 的索引文件中仅保存了数据的地址,所以在 MyISAM 中主索引和辅助索引在结构上没有本质的区别,只是主索引要求 key 的唯一性,而辅助索引的 key 是可以重复的。

Since the data stored MyISAM field address data is recorded, so MyISAM index search algorithm first search algorithm in accordance with the B + Tree search index, if the specified key is present, then the value of the data field extracted, and then the value of the data field as an address, reads the corresponding data record.

MyISAM indexes mode is also called "non-clustered", the reason so called to distinguish the InnoDB clustered index.

The difference between MyISAM and InnoDB

  1. The transaction

    MyISAM: it emphasizes that performance, speed queries faster than InnoDB type, but does not provide transaction support.

    InnoDB: providing transaction support.

  2. Foreign key

    MyISAM: does not support foreign keys.

    InnoDB: support foreign keys.

  3. lock

    MyISAM: supports only table-level locking.

    InnoDB: supports row-level locking and table-level locking, the default is row-level locks, row locks greatly improve the performance of multi-user concurrent operations. InnoDB is more suitable for relatively large number of inserts and updates situation, but MyISAM is applicable to the case of frequent queries. In addition, InnoDB row lock table is not absolute, if you execute a SQL statement, MySQL can not determine the range to be scanned, InnoDB tables will also lock the whole table, for example: update table set num=1 where name like '%aaa%';.

  4. Full Text Search

    MyISAM: support for full-text search.

    InnoDB: does not support full-text search.

  5. Table's primary key

    MyISAM: Allow Table no primary key exists.

    InnoDB: If no primary key, a 6-byte is automatically generated primary key (not visible to users).

  6. Specific number of rows in the table

    MyISAM: select count(*) from table, MyISAM simply read out the saved line number. Because MyISAM built-in counter, when the count (*) which read directly from the counter.

    InnoDB: a specific number of lines do not save the table, that is, execution select count(*) from tabletime, InnoDB again to scan the entire table to calculate how many rows.

    This article from the blog article multiple platforms OpenWrite release!

Guess you like

Origin www.cnblogs.com/Jacian/p/12145696.html