mysql执行原理 索引 锁简介

2018-08-21  本文已影响0人  小绵羊你毛不多

mysql走你~~

select * form table where id=?

一条mysql查询都会经历些什么呢?

image
  1. 客户端向MySQL服务器发送一条查询请求
  2. 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段
  3. 服务器进行SQL解析、预处理、再由优化器生成对应的执行计划
  4. MySQL根据执行计划,调用存储引擎的API来执行查询
  5. 将结果返回给客户端,同时缓存查询结果

索引规则

  1. 索引并不是越多越好,要根据查询有针对性的创建,考虑在WHERE和ORDER
  2. BY命令上涉及的列建立索引,可根据EXPLAIN来查看是否用了索引还是全表扫描
  3. 应尽量避免在WHERE子句中对字段进行NULL值判断,否则将导致引擎放弃使用索引而进行全表扫描
  4. 值分布很稀少的字段不适合建索引,例如"性别"这种只有两三个值的字段
  5. 字符字段只建前缀索引

mysql大表优化

索引

索引(Index)是帮助MySQL高效获取数据的数据结构。本质上,索引是一种数据结构

先来聊聊b-tree(b树,不是b减树) b+tree

B-Tree

image

为了定义b-tree 首先定义一个二元组[key,data],key为记录的键值,对于不同数据记录,key是互不相同的;data为数据记录除key外的数据。那么B-Tree是满足下列条件的数据结构:

查找

BTree_Search(node, key) {
    if(node == null) return null;
    foreach(node.key)
    {
        if(node.key[i] == key) return node.data[i];
            if(node.key[i] > key) return BTree_Search(point[i]->node);
    }
    return BTree_Search(point[i+1]->node);
}
data = BTree_Search(root, my_key);

B+Tree

带有顺序访问指针的B+Tree

image
  1. 内节点不存储数据,只存储key,叶子节点不存储指针。
  2. 每个节点的指针上线不是2d 是2d+1

局部性原理与磁盘预读

当一个数据被用到时,其附近的数据也通常会马上被使用。程序运行期间所需要的数据通常比较集中

B-/+Tree索引的性能分析

Mysql 索引实现

mysql有MyISAM和InnoDB两个存储引擎,分别讨论实现方式。

MyISAM索引实现
image
InnoDB索引实现
image image
小优化

索引使用策略及优化

MySQL的优化主要分为结构优化(Scheme optimization)和查询优化(Query optimization)。下面讨论的是结构优化。

建索引的几大原则

MySQL中的索引可以以一定顺序引用多个列,这种索引叫做联合索引。单列索引可以看成联合索引元素数为1的特例。

事务隔离级别

隔离级别 脏读 不可重复读 幻读
未提交读 Read uncommitted 可能 可能 可能
已提交读 Read commited 可能 可能
可重复读(默认)Rrepeatable read 可能
可串行化 Serializable

myisam innodb

为什么选择innodb

参考文章
MyISAM 有表锁
Innodb行级锁,

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

悲观锁:假设会发生并发冲突,屏蔽一切可能违反数据完成性的操作。

Innodb锁类型包括

共享锁与独占锁 意向锁

实现了两种方式的行锁:

设置共享锁 SELECT ** LOCK IN SHARE MODE;
设置排他锁 Select ** for update;

共享锁和意向共享锁 区别

Innodb 行锁实现方式

是通过索引上的索引项来实现的。这就意味着:

行锁( 记录锁 间隙锁 next key)

只有在可重复读及以上 才有gap和next key

record lock 记录锁
gap lock 间隙锁

参考

id v1
1 1
2 3
3 4
5 5
7 7
10 9

表中v1字段值可以划分的区间为

(-∞,1)

(1,3)

(3,4)

(4,5)

(5,7)

(7,9)

(9, +∞)

加入要更新v1=7的数据行,也就是对v1加上间隙锁,区间是(5,7)(7,9)

session 1
select * from tem where v1=7 for update
//会在(5,5)(7,7)之间加间隙锁
//会在(7,7)(10,9)之间加间隙锁
session2
insert tmp
value(4,5)  成功
value(8,8)   阻塞
value(6,6)   阻塞
value(11,9)  成功
value(12,7) 会成功吗?

间隙锁2 条件范围的

目的:

问题:

next key lock

什么时候使用表锁

绝大多数情况下,都应该使用行级锁。但是特殊情况,比如

关于死锁

死锁情况分析
常见sql加锁情况分析
死锁常见情况分析
定义:

关键:

发生死锁后,innodb一般可以自动检测到,并使一个事务释放锁并退回,另一个事务获得锁,继续完成事务。

但是并不能完全检测到死锁。可以通过设置锁等待超时时间来解决。

死锁情况分析

  1. 用户访问A表之后访问B 另一用户,访问B之后访问A 互相等待释放锁,导致死锁
  2. 在一个不走索引的更新上,会导致全表加锁,多个的话,会导致死锁。

案例1

事务1 事务 2
select * from user where id=1 for update -
- select * from user where id=2 for update
update user set name='' where id=2 由于被事务2加锁 只能阻塞
- update user set name='' where id=1 由于被事务1加锁 只能阻塞 此时Innodb检测出死锁,事务回滚
事务2回滚 update继续执行
commit

案例二

现在表中没有id=8 和id=9的数据

事务1 事务 2
update user set name="" where id=8 会在>8的范围加间隙锁
.- update user set name="" where id=9 会在>9的范围加间隙锁 间隙锁之间不冲突
insert into user(id) value(8) 这个时候需要等待事务2释放间隙锁
.- insert into user(id) value(9) 这个时候需要等待事务1释放间隙锁

解决办法 就是去掉上面的update语句

案例三

事务 1 事务 2
update user set name="" where id<20 update user set name="" where id>15

加锁顺序不一样,会导致死锁。

最后

任何数据库层面的优化都抵不上应用系统的优化。查询容易,优化不易,且写且珍惜

上一篇 下一篇

猜你喜欢

热点阅读