自增主键分为两种,一种是显性的,一种是隐性的(row_id)。如果是显性的,那么就会报主键冲突错误,

如果是隐性的,下次申请ID的时候,得到的值会从0开始,然后继续开始自增,但这个时候会覆盖原有相同

row_id的数据

显性的一般是bigint,unsign

这样的话,肯定是自己显性指定主键ID,毕竟这样的话异常我们才能感知到的

真用完了怎么办?

1.脚本扫描没用到的主键,然后插入,但不推荐,会破坏其原有数据的连续性

2.将表里的久远数据归档(推荐)

3.使用UUID,UUID是128位,几乎不可能用完的,但不推荐,UUID作为主键ID容易造成页分裂,页合并

count(1) count() count(列名) 哪个性能高?
count(1)和count(
) 表示直接查询符合where条件的行数,而count(列名)表示查询的列名不为

空且符合where条件的行数。count(*)是要比count(1)性能高,因为它是标准语法,MySQL对它进行了

很多优化

count(*)的优化?

首先声明一点,优化的前提是使用count(*)时不带where和group by

- 对于myisam而言,因为它锁的粒度最小只有表锁,所以它不会有并发的行数据修改,故MySQL采用了一个字段进行存储它的行数
- 对于InnoDB而言,MySQL进行count(*) 时会选择一个最小非聚簇索引,因为count时他是不会关心你具体数据的,而非聚簇索引的叶子结点装的是主键ID,比聚簇索引小。所以建索引时,再建一个非聚簇索引也是必要的

count(列名)?
count(1)和count(*)只是扫描索引树,而count(列名)则需要进行全表扫描,如果列名不加索引

大数据量统计下,可以怎么优化count(*)

1.如果对count的精准要求不高,可以通过explain里的row代替

2.用一张表维护count,insert就+1,或者delete就 -1

3.用列式存储数据库,如click house

数据库查询优化的一种手段,它就是说多个索引同时检索来提高查询效率,类似于我们开多线程

通过explain,我们可以清晰地看到用到了索引合并的标识 index_merge

并且可以在extra 看到使用了哪种策略

using interset:

using union:

using sort_union:

查询的字段被包含在了索引里,不需要回表了,这就是索引覆盖

首先我们要明白采用它的目的,一定就是要时间复杂度尽可能地小,支持范围查询。前者无非就是树,跳表,Hash表。而hash索引不支持范围查询

为什么不用Hash?

不支持范围查询

为什么不用跳表?

跳表是内存友好型,而b+树是磁盘友好型。b+树一般在磁盘里寻址三次足以,每次都会读取一个数据页,然

后在数据页进行二分查找

而跳表每次读取一个数据页节点都需要跳跃,而链表又是几万个节点,虽然是logn,但寻址次数明显是要比

b+树多,因为b+树的二分查找主要是在数据页中(已经读到内存中了,InnoDB是读到bufferpool,myisam

是读到 page cache),而跳表的二分查找就是在链表中,即磁盘中,而且索引之间的物理距离可能比较长

为什么不用b树?

b树的非叶子节点的v也会存数据,这导致一个页中存储的kv值会减少(因为一个页的大小是固定的),指针

就会表少,要同样保存大量数据,就得去增加树高,导致其性能降低。然后就是叶子节点之间是没有指针相连

的,对范围查询不是很友好,且叶子节点之间是无指针相连的,对范围查询不是很友好

为什么不用二叉树/红黑树?

二叉树层级过高,搜索效率偏低,百万数据约为20层

补:

%北%走索引的,但是%北%无法二分查找啊,这下索引就没卵用了,因为只会全扫

– 1.索引也是会全扫描的

– 2.mysql加载16k一页,全扫索引比全扫主键快很多,IO快,列差得很大,快很多,因为你拿数据拿得多啊,二级索引树就拿了ID+列名,你主键拿的是一行,即所有列的数据

将SQL语句转成物理执行计划,并以最小化查询时间or资源消耗

工作流程

  1. 将SQL转成抽象语法树

2.重写查询:简化条件,合并子查询、消除冗余操作

3.根据模型评估执行计划,选择最小成本计划(选哪个索引)

4.将最优计划转换为可执行的指令集

是什么?

  假如有一个联合索引(A,B,C),如果你想要命中这个联合索引,where就得包含最左列即A。

且where a b c的顺序不影响索引的命中

为什么得遵循?

联合索引的索引树示例结构 (age,name)

那他是怎么构造索引树的呢,首先会根据联合索引中字段的位置来决定谁先排序。如果age不同,会先对

age进行排序,如果age相同,再进行name的排序。

那么就可以很好理解最左匹配原则了:因为索引的底层是b+树,如果是联合索引的话,在构造索引树时,

会先按左边的字段进行排序,左边的key相同时再根据右边的字段排序

MySQL8.0引入的索引跳跃机制

索引跳跃机制

MySQL不同隔离级别下的加锁情况 | Exploring

MySQL/mysql-storage-engines/innodb/1.5.5.InnoDB锁——lock之不同SQL加锁分析.md at master · asdbex1078/MySQL

抛开隔离级别谈上锁都是耍流氓!

读未提交

- 增:插入数据后,给新插入的数据上<font style="color:#DF2A3F;">记录锁</font>,防止其它事务更改这条记录 
- 删:需要获取到要删除的记录的<font style="color:#DF2A3F;">记录锁</font>,保证删除的时候其它事务没在使用这些数据,并保证删除后其它事务无法对这些数据进行操作 
- 改:给需要更改的数据上<font style="color:#DF2A3F;">记录锁 </font>
- 查:任何读都不加锁

读已提交

- 增:插入数据后,给新插入的数据上<font style="color:#DF2A3F;">记录锁</font>,防止其它事务更改这条记录 
- 删:需要获取到要删除的记录的<font style="color:#DF2A3F;">记录锁</font>,保证删除的时候其它事务没在使用这些数据,并保证删除后其它事务无法对这些数据进行操作 
- 改:给需要更改的数据上<font style="color:#DF2A3F;">记录锁 </font>
- 查:快照读不加锁,当前读只加记录锁

可重复读

- 增:使用<font style="color:#DF2A3F;">插入意向锁</font>,进行插入,插入后给插入的数据上<font style="color:#DF2A3F;">记录锁</font>(隐式锁,其实这个记录锁不是这个时候上的) 
- 删:使用<font style="color:#DF2A3F;">临键锁</font>,防止其它事务在删除的区间内插入数据 
- 改:给需要更改的数据上<font style="color:#DF2A3F;">临键锁 </font>
- 查:快照读不加锁,当前读:加临键锁和间隙锁,唯一索引则加记录锁

序列化

- 增:使用<font style="color:#DF2A3F;">插入意向锁</font>,进行插入,插入后给插入的数据上<font style="color:#DF2A3F;">记录锁</font>(隐式锁,其实这个记录锁不是这个时候上的) 
- 删:使用<font style="color:#DF2A3F;">临键锁</font>,防止其它事务在删除的区间内插入数据 
- 改:给需要更改的数据上<font style="color:#DF2A3F;">临键锁</font> 
- 查:普通查询自动变为select … lock in share mode,上<font style="color:#DF2A3F;">临键锁,锁间隙</font>! 唯一索引加记录锁

细节

锁的对象是索引,而不是记录

二级索引的记录加了排他锁,聚簇索引也会加对应的锁。

如果没有合适的索引,那么MySQL就会扫表来处理,那么表的每一行都会被锁定,从而阻塞其他用户对 表的所有插入

临键锁只存在于可重复读和串行化事务隔离级别下

MVCC只存在于读已提交和可重复读

next-key lock 是前开后闭((x,y])区间,而间隙锁是前开后开区间((x,y))

临键锁上锁的优化:

临键锁锁的是一个间隙以及一个间隙后面的行记录,锁粒度比较大,在一些情况下会对其进行一定优化

总结起来就是 在加间隙锁or记录锁能避免幻读的情况下,临键锁就会退化成记录or间隙

唯一索引等值查询:

当查询的记录存在时,定位到了在索引树上的位置,那么原先在扫描时加的临键锁就会退化成记录锁

当查询的记录不存在时,在索引树找到比它大的第一条记录时,那么临建锁就会退化成 间隙锁

唯一索引范围查询情况

唯一索引扫描索引树时,会对扫描到的每一个索引加临键锁,如果满足一些条件就有可能发生锁退化

非唯一索引等值查询

非唯一索引范围查询情况

临键锁无法进行退化

非索引扫描情况

每一条记录的索引上都会加 next-key 锁,这样就相当于锁住的全表**:****从负无穷到正无穷(全表记**

录 + 所有间隙)

以上加锁的机制都是围绕着如何避免幻读来展开的

ps:锁全表的数据(临建锁)时,那这时候往表的最后一行后插入数据会被阻塞吗。会的,锁到正无穷,如果插入头部,负无穷也会被锁住

MySQL只操作同一条记录,也会发生死锁吗?

会的。mysql锁的是索引,而不是记录。如果是根据二级索引查询(加锁查询orDML),那么它会

先获取二级索引上的锁,然后再去对主键索引上的锁。如果有两线程同时获取锁的顺序不一样了,

那么就会发生死锁

加锁原则:两个原则两个优化一个bug