Step by step you started MySQL with the index and lock (turn)

Source:  Step by step you started MySQL with the index and lock

 

index

Index common types

Index common types of hash index, orderly array index, the index binary tree, jump table , and so on. This article discusses the default MySQL storage engine InnoDB index structure.

InnoDB index structure

Multiplexing is achieved by a search tree in InnoDB - B + tree to achieve index structure. B + Tree is only leaf node stores data , and all leaf nodes form a linked list . And maintained in InnoDB is a doubly linked list.

 

You may have a question, why the use of B + trees without the use of a binary tree or B-tree?

First, we need to know to access the disk to access the specified block, and the block is required to access the specified disk rotation and magnetic arm movement , which is a relatively time-consuming process, if the increase in tree height then it means you need to be more disk access times , so will the use of n-tree. B + tree is used because using the B-tree during a time range of each time re-lookup retrieval, while B + Tree can take advantage of a linked list of leaf node .

In the construction of the table when you might add multiple indexes, and InnDB will build a B + tree index is stored for each index .

For example, this time we have created a simple test table

create table test(
  id int primary key,
  the int  not  null ,
  name varchar,
  index(a)
)engine = InnoDB;

This time InnDB will build two B + tree index for us

One is the primary key of a clustered index , the other is the ordinary index of secondary indexes , and here I direct Paste MySQL Discussion (index, lock) the article above map (lazy because I do not want to draw a ...)

It can be seen in the above index value of the auxiliary leaf nodes only stored primary key value , and the leaf nodes clustered index on the primary key value is stored on the entire record .

Back to the table

So here we will come out of a concept called back to the table , like this time we were a query operation

select name from test where a = 30;

我们知道因为条件 MySQL 是会走 a 的索引的,但是 a 索引上并没有存储 name 的值,此时我们就需要拿到相应 a 上的主键值,然后通过这个主键值去走 聚簇索引 最终拿到其中的name值,这个过程就叫回表。

我们来总结一下回表是什么?MySQL在辅助索引上找到对应的主键值并通过主键值在聚簇索引上查找所要的数据就叫回表

索引维护

我们知道索引是需要占用空间的,索引虽能提升我们的查询速度但是也是不能滥用。

比如我们在用户表里用身份证号做主键,那么每个二级索引的叶子节点占用约20个字节,而如果用整型做主键,则只要4个字节,如果是长整型(bigint)则是8个字节。也就是说如果我用整型后面维护了4个g的索引列表,那么用身份证将会是20个g。

所以我们可以通过缩减索引的大小来减少索引所占空间

当然B+树为了维护索引的有序性会在删除,插入的时候进行一些必要的维护(在InnoDB中删除会将节点标记为“可复用”以减少对结构的变动)。

比如在增加一个节点的时候可能会遇到数据页满了的情况,这个时候就需要做页的分裂,这是一个比较耗时的工作,而且页的分裂还会导致数据页的利用率变低,比如原来存放三个数据的数据页再次添加一个数据的时候需要做页分裂,这个时候就会将现有的四个数据分配到两个数据页中,这样就减少了数据页利用率。

覆盖索引

上面提到了 回表,而有时候我们查辅助索引的时候就已经满足了我们需要查的数据,这个时候 InnoDB 就会进行一个叫 覆盖索引 的操作来提升效率,减少回表。

比如这个时候我们进行一个 select 操作

select id from test where a = 1;

这个时候很明显我们走了 a 的索引直接能获取到 id 的值,这个时候就不需要进行回表,我们这个时候就使用了 覆盖索引

简单来说 覆盖索引 就是当我们走辅助索引的时候能获取到我们所需要的数据的时候不需要再次进行回表操作的操作

联合索引

这个时候我们新建一个学生表

CREATE TABLE `stu` (
  `id` int(11) NOT NULL,
  `class` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `class_name` (`class`,`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

我们使用 class(班级号) 和 name 做一个 联合索引,你可能会问这个联合索引有什么用呢?我们可以结合着上面的 覆盖索引 去理解,比如这个时候我们有一个需求,我们需要通过班级号去找对应的学生姓名

select name from stu where class = 102;

这个时候我们就可以直接在 辅助索引 上查找到学生姓名而不需要再次回表。

总的来说,设计好索引,充分利用覆盖索引能很大提升检索速度

最左前缀原则

这个是以 联合索引 作为基础的,是一种联合索引的匹配规则。

这个时候,我们将上面的需求稍微变动一下,这时我们有个学生迟到,但是他在门卫记录信息的时候只写了自己的名字张三而没有写班级,所以我们需要通过学生姓名去查找相应的班级号。

select class from stu where name = '张三';

这个时候我们就不会走我们的联合索引了,而是进行了全表扫描

为什么?因为 最左匹配原则。我们可以画一张简单的图来理解一下。

我们可以看到整个索引设计就是这么设计的,所以我们需要查找的时候也需要遵循着这个规则,如果我们直接使用name,那么InnoDB是不知道我们需要干什么的。

 

当然最左匹配原则还有这些规则

  • 全值匹配的时候优化器会改变顺序,也就是说你全值匹配时的顺序和原先的联合索引顺序不一致没有关系,优化器会帮你调好。
  • 索引匹配从最左边的地方开始,如果没有则会进行全表扫描,比如你设计了一个(a,b,c)的联合索引,然后你可以使用(a),(a,b),(a,b,c) 而你使用 (b),(b,c),(c)就用不到索引了。
  • 遇到范围匹配会取消索引。比如这个时候你进行一个这样的 select 操作
select * from stu where class > 100 and name = '张三';

这个时候 InnoDB 就会放弃索引而进行全表扫描,因为这个时候 InnoDB 会不知道怎么进行遍历索引,所以进行全表扫描。

索引下推

我给你挖了个坑。刚刚的操作在 MySQL5.6 版本以前是需要进行回表的,但是5.6之后的版本做了一个叫 索引下推 的优化。

select * from stu where class > 100 and name = '张三';

如何优化的呢?因为刚刚的最左匹配原则我们放弃了索引,后面我们紧接着会通过回表进行判断 name,这个时候我们所要做的操作应该是这样的

但是有了索引下推之后就变成这样了,此时 "李四" 和 "小明" 这两个不会再进行回表。

因为这里匹配了后面的name = 张三,也就是说,如果最左匹配原则因为范围查询终止了,InnoDB还是会索引下推来优化性能。

一些最佳实践

哪些情况需要创建索引?

  • 频繁作为查询条件的字段应创建索引。
  • 多表关联查询的时候,关联字段应该创建索引。
  • 查询中的排序字段,应该创建索引。
  • 统计或者分组字段需要创建索引。

哪些情况不需要创建索引

  • 表记录少。
  • 经常增删改查的表。
  • 频繁更新的字段。
  • where 条件使用不高的字段。
  • 字段很大的时候。

其他

  • 尽量选择区分度高的列作为索引。
  • 不要对索引进行一些函数操作,还应注意隐式的类型转换和字符编码转换。
  • 尽可能的扩展索引,不要新建立索引。比如表中已经有了a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
  • 多考虑覆盖索引,索引下推,最左匹配。

全局锁

MySQL提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。

一般会在进行 全库逻辑备份 的时候使用,这样就能确保 其他线程不能对该数据库做更新操作

在 MVCC 中提供了获取 一致性视图 的操作使得备份变得非常简单,如果想了解 MVCC 可以参考我的另一篇文章 你真的懂MVCC吗?来手动实践一下?

表锁

MDL(Meta Data Lock)元数据锁

MDL锁用来保证只有一个线程能对该表进行表结构更改

怎么说呢?MDL分为 MDL写锁MDL读锁,加锁规则是这样的

  • 当线程对一个表进行 CRUD 操作的时候会加 MDL读锁
  • 当线程对一个表进行 表结构更改 操作的时候会加 MDL写锁
  • 写锁和读锁,写锁和写锁互斥,读锁之间不互斥

lock tables xxx read/write;

这是给一个表设置读锁和写锁的命令,如果在某个线程A中执行lock tables t1 read, t2 write; 这个语句,则其他线程写t1、读写t2的语句都会被阻塞。同时,线程A在执行unlock tables之前,也只能执行读t1、读写t2的操作。连写t1都不允许,自然也不能访问其他表。

这种表锁是一种处理并发的方式,但是在InnoDB中常用的是行锁

行锁

我们知道在5.5版本以前 MySQL 的默认存储引擎是 MyISAM,而 MyISAM 和 InnoDB 最大的区别就是两个

  • 事务
  • 行锁

其中行锁是我们今天的主题,如果不了解事务可以去补习一下。

其实行锁就是两个锁,你可以理解为 写锁(排他锁 X锁)和读锁(共享锁 S锁)

  • 共享锁(S锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。 也叫做读锁:读锁是共享的,多个客户可以同时读取同一个资源,但不允许其他客户修改。

  • 排他锁(X锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。也叫做写锁:写锁是排他的,写锁会阻塞其他的写锁和读锁。

而行锁还会引起一个一个很头疼的问题,那就是死锁

如果事务A对行100加了写锁,事务B对行101加了写锁,此时事务A想要修改行101而事务B又想修改行100,这样占有且等待就导致了死锁问题,而面对死锁问题就只有检测和预防了。

next-key锁

MVCC and row lock can not be solved phantom read problem, this time called InnoDB uses a GAP lock (lock gap) things, which with the row lock to form a next-key lock to solve the problem of phantom reads.

But because it's locking rules, it has led to the expansion of the scope to reduce the number of database locking concurrency. Specific locking rules as follows:

  • The basic unit is locked is the row next-key lock locking joint locks and GAP.
  • Find objects during the visit will be to lock.
  • Equivalent queries on the index, the only index to lock when, next-key lock degenerate into row lock.
  • Equivalent query on the index, while traversing right and the last value does not satisfy the equivalent conditions when, next-key lock lock degenerate into space.
  • Range of unique index on the query access until the value does not satisfy the first condition.

MVCC ideas to solve more complex phantom read here is not to do too much verification.

to sum up

The index for MySQL, I gave a lot of best practices, these best practices are in fact from the principle, while InnoDB is actually a B + tree structure, as well as to store the index improved version. These handy and you'll understand it.

For MySQL locks, the main aspect is the line lock, InnoDB is actually using a row lock, MVCC as well as next-key locks to implement transaction concurrency control .

 

Guess you like

Origin www.cnblogs.com/myseries/p/11791259.html