M y s q l 篇

目录

1、索引的基本原理

索引是什么:

索引的原理:

步骤:

2、MySQL聚簇和非聚簇索引的区别

相同点:

聚簇索引:

非聚簇索引:

优势:

劣势:

InnoDB:

MyISM:

3、MySQL索引的数据结构,各自优劣

B+树:

哈希索引:

4、索引设计的原则

5、什么是最左前缀原则?什么是最左匹配原则?

最左前缀匹配原则:

6、锁的类型有哪些

属性

共享锁(share lock):

排他锁(exclusive lock):

粒度

表锁:

行锁:

记录锁(Record Lock):

页级锁:

间隙锁(Gap Lock):

临建表(next-key lock):

意向锁是什么呢:

意向共享锁:

意向排他锁:

7、InnoDB存储引擎的锁的算法

例子:

8、关心过业务系统里面的sql耗时问题嘛?统计过慢查询嘛?对于慢查询都是怎么优化过度的?

9、事务的基本特性和隔离级别

(A)原子性:

(C)一致性:

(I)隔离性:

(D)持久性:

隔离性有四个级别

read uncommit(读未提交):

read commit(读并提交):

repeatable read(可重复读):

serializable(串行 理解就好):

脏读(Dirty Read):

不可重复读(Non-repeatable read):

幻读(Phantom Read):

10、ACID靠什么保证呢? 

                

11、什么是MVCC

多版本并发控制:

聚簇索引记录中有两个必要的隐藏列:

12、分表后非sharding_key的查询怎么样处理,分表后的排序?

        

(1)可以先做一个mapping表

(2)宽表,对数据实时性要求不是很高的场景。

(3)数据量不是很大的话

union

13、mysql主从同步原理

mysql的主从同步的过程

mysql的主从复制主要有三个线程:

注意:

全同步复制:

半同步复制:

14、简述下MyISAM和InnoDB的区别

MyISAM:

InnoDB:

15、简述下mysql中索引类型及对数据库的性能的影响

普通索引:

唯一索引:

主键索引:

联合索引:

组合索引:

全文索引:

16、mysql的执行计划

SQL编写顺序:        

SQL执行的优先级:

(1)id:

(2)selectType:

(3)table:

(4)type:

执行效率:

(5)possible_key:

(6)key:

(7)key_len:

(8)rows:

(9)filtered:

(10)extra:

17、什么是快照读和当前读

18、B树和B+树有什么区别,为什么会使用B+树

19、哪些情况索引会失效

20、MySQL内连接、左连接、右连接的区别

21、如何设计数据库

22、where和having的区别

23、char和varchar区别

24、InnoDB什么情况下会产生死锁

mysql解决死锁的机制有两个:

死锁的检测原理:

25、MySQL删除自增id,随后重启MySQL服务,再插入数据,自增id会从几开始

InnoDB引擎:

MyISAM:


1、索引的基本原理

索引是什么:

  • 索引用来快速的寻找具有特定值的记录。如果没有索引,一般来说执行查询的时候就会遍历整张表。

索引的原理:

  • 就是把无序的数据变成有序的查询

步骤:

  1. 把创建了的索引的列的内容进行排序
  2. 对排序结果生成倒排表
  3. 在倒排表内容上拼上数据地址链
  4. 在查询的时候,先拿到倒排表的内容,再取出数据地址链,从而拿到具体数据

        简单点理解就是首先要把创建了的索引的列的内容进行排序,对排序的结果生成倒排表,然后在倒排表的内容中拼接上数据地址链。最后在查询的过程中先拿倒排表的内容,再取出数据地址链,最后拿到数据。


2、MySQL聚簇和非聚簇索引的区别

相同点:

  • 它们都是b+树的数据结构

聚簇索引:

  1. 它是将数据存储与索引放到一块,并且是按照一定的顺序组织的,也就是说找到索引也就找到了数据。
  2. 数据的物理存放顺序和索引顺序是一致的。
  3. 其实就是只要索引是相邻的,那么对应的数据一定也是相邻的存放在磁盘上

        就是将索引和值放在了一起,然后根据索引就可以直接获取值。如果主键值很大的话,辅助索引也会变得很大,如果用uuid作为主键,那么数据存储会变得很稀疏

非聚簇索引:

  1. 叶子节点不存储数据、存储的是数据行地址。
  2. 也就是说只要根据索引查找到数据行的位置,再取磁盘查找到数据就可以。
  3. 这个就有点类似一本书的目录,比如我们要找到第三章的第一节,那我们先在这个目录里面找对应的内容查看对应的页码,找到对应的页码后再去对应的页码看文章

        叶子节点存放的是数据行地址,我们要先根据索引找到数据地址,然后在根据地址去找数据

优势:

  • 查询通过聚簇索引可以直接获取数据,相比于非聚簇索引需要第二次查询效率要高(就是聚簇可以直接获取数据,它的效率会更高,因为非聚簇需要经过两次查询才能找到数据)
  • 聚簇索引对于范围查询的效率很高,因为其数据是按照大小排列的
  • 聚簇索引适合用于在排序的场合,非聚簇索引不适合用于排序场合

劣势:

  • 维护索引的费用是很高的,特别是插入新行或者主键的时候如果要被更新导致分页的时候。

解决:建议在大量插入新行后,选择在负载较低的时间段,通过optimize table去优化表。因为被动的行数据可能会造成碎片。使用独享表空间可以弱化碎片。

  • 表因为使用了随机id作为主键,使得数据存储变得稀疏。可能会出现聚簇索引效率变慢

解决:这个时候建议使用int的auto_increment作为主键

  • 如果主键比较大的话,那么辅助索引将会变得更大。

原因:因为辅助索引的叶子存储的是主键值,过长的主键值,会导致非叶子节点占用更多的物理空间

InnoDB:

  • 它里面一定有主键,主键一定是聚簇索引。
  • 如果它不用手动设置,那么它就会使用unique索引。如果没有unique索引,就会使用数据库内部的一个行的隐藏id来当做主键索引。
  • 在聚簇索引之上创建的索引,被称为辅助索引。
  • 辅助索引访问数据总是需要二次查找。
  • 非聚簇索引都是辅助索引。
  • 辅助索引的叶子节点存储的不再是行的物理位置,而是主键。

MyISM:

  • 它使用的是非聚簇索引,没有聚簇索引。
  • 非聚簇索引的两颗B+树看上去没什么不同。它们的节点结构完全一致,只是存储的内容不同而已。
  • 主键索引的B+树存储了主键,辅助键索引的B+树存储了辅助键。
  • 表数据存储在独立的地方,这两颗B+树的叶子节点都使用了一个地址指向真正的表数据。
  • 对于表数据来说,这两个键没有任何差别。
  • 由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

        如果涉及到大数据的排序,全表扫描、count之类的操作话,还是MyISAM占有优势。因为索引所占空间小,这些操作都需要在内存中完成的。


3、MySQL索引的数据结构,各自优劣

索引的数据结构和具体存储引擎的实现是有关系的。在MySQL中使用比较多的索引有Hash索引和B+树索引。

  • InnoDB存储引擎的默认索引实现为:B+树索引
  • 就是对于哈希索引来说,底层的数据结构就是哈希表。
  • 因为在绝大多数需求为单条记录查询的时候,可以选择哈希索引,它的查询性能是最快的。
  • 其余的大部分场景建议使用BTree索引

B+树:

  • B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接。
  • 在B+树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大幅度波动。
  • 而且基于索引的顺序扫描的时候,也可以利用双向指针快速左右移动,效率非常高。
  • 因此,B+树索引被广泛应用于数据库、文件系统场景等。

哈希索引:

  • 哈希索引就是采用一定的哈希算法,把键值换算成新的哈希表
  • 检索的时候不需要类似像B+树那样从根节点到叶子节点逐渐查找
  • 它只需要一次哈希算法就可以立刻定位到相应的位置,速度非常快

如果是等值查询的话,那么哈希索引就有明显的绝对优势。

  • 因为哈希索引只需要经过一次的算法就可以找到相应的键值。前提是键值都是唯一的哈。
  • 如果键值不是唯一的,就需要先找到该键所在的位置,然后再根据链表往后扫描,直到找到相应的数据。

如果是范围查询检索的话,这个时候哈希表索引就毫无用武之地了。

  • 因为原先是有序的键值,经过哈希算法之后,有可能变成不连续的了。就没办法再利用索引完成范围查询检索了。  
  • 哈希索引也没有办法利用索引完成排序,也不支持多列联合索引的最左匹配原则
  • B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大。在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在哈希碰撞的问题


4、索引设计的原则

查询更快、占用空间更小

(1)适合索引的列是出现在where子句的列中,或者连接子句中指定的列中

(2)基数较小的表,索引效果较差,没有必要在这里建立索引了

(3)在使用短索引的时候,如果对长字符串的列进行索引的话,应该指定一个前缀长度,这样能够节省出大量的索引空间。

  • 如果搜索词超过索引前缀的长度,则使用索引排除不匹配的行,然后检查其余的行是否可能匹配。

(4)不要过度去使用索引。

  • 索引需要额外的磁盘空间,并且降低操作的性能。
  • 在修改表的内容的时候,索引会进行更新甚至是重构造。索引列越多,这个时间就会越长。所以只我们只需要保持需要的索引就可以,这样有利于查询。

(5)定义有外键的数据列一定要建立索引

(6)更新频繁的字段不适合创建索引

(7)如果是不能有效区分数据的列表,就不适合做索引列表

(8)尽量的扩展索引,不要新建索引。

  • 比如表中已经有了a的索引,现在要加(a,b)索引,那么只需要修改原来的索引就可以了

(9)对于那些查询种很少涉及的列,重复值比较多的列,就不要建立索引

(10)对于定义为text、image和bit的数据类型的列表,也不要建立索引


5、什么是最左前缀原则?什么是最左匹配原则?

就是最左优先的意思。

  • 在创建多列索引的时候,要根据业务需求,where子句中使用最频繁的一列放到最左边。

最左前缀匹配原则:

  • mysql在匹配的过程中会一直向右边匹配直到遇到范围查询(between和like)就会停止匹配。

举个例子:

  • a=1 and b=2 and c=3 and d=4,如果建立(a,b,c,d)顺序的索引,d是用不到索引的
  • a=1 and b=2 and d=4 and c=3,如果建立(a,b,d,c)的索引则都可以用的到,a,b,d的顺序可以进行任意调整
  • = 和 in是可以乱序的。比如 a=1 and b=2 and c=3建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化生成索引可以识别的形式


6、锁的类型有哪些

  • 基于锁的属性分类:共享锁和排他锁
  • 基于锁的粒度分类:行级锁(INNODB)、表级锁(INNODB、MYISAM)、页级锁(BDB引擎)、记录锁、间隙锁、临键锁
  • 基于锁的状态分类:意向共享锁、意向排他锁

  • 表级锁:对整张表加锁,粒度大并发小
  • 行级锁:对行加锁,粒度小并发大
  • 间隙锁:锁住表的一个区间,间隙锁之间不会冲突只在可重复读下才生效,解决了幻读问题
  • 共享锁:又叫读锁,一个事务为表加了共享锁之后,其他的事务只能加共享锁,不能加排他锁
  • 排他锁:又叫写锁,一个事务加了排他锁之后,其他的事务就不能加任何其他的锁了,避免了脏读问题

属性

共享锁(share lock):

  • 它又叫做读锁,简称叫S锁。
  • 当一个事务帮数据加上共享锁之后,其他的事务就只能对该数据加上共享锁,而不能对数据加排他锁。要等到所有的共享锁释放之后,其他的事务才能对其进行加排他锁的操作。
  • 共享锁的特点主要是为了支持并发的读取数据。在读取数据的时候,记住不支持修改。避免会出现重复读的问题。(它只支持并发读取,但不支持修改,因为会出现重复度的问题)

        其实就是如果先加了共享锁,那么其他的事务就只能加共享锁,不能加其他锁。要等到全部共享锁释放了,才能够加其他锁。

排他锁(exclusive lock):

  • 它又叫做写锁,简称X锁。
  • 当一个事务帮数据加上排他锁的时候,其他的请求就不能够在为数据加上任何锁了。要等到该锁释放完之后,其他的事务才能对数据进行一个加锁操作。
  • 排他锁的目的是在数据修改的时候,不允许其他的人同时修改数据,也不允许其他人读取。避免了出现脏数据和脏读的问题。

        当一个事务加了排他锁之后,就不能够在上面加任何锁的操作了。只有当排他锁释放完之后,其他的事务才能够对数据进行加锁操作

粒度

表锁:

  • 它是指上锁的时候锁住的是整个表。
  • 当下一个事务去访问该表的时候,必须等到前一个事务释放了锁才能进行对该表的进行访问。
  • 特点:粒度大,加锁简单,容易冲突

        其实表锁就是它一上锁就是锁住了整个表,如果下一个事务要访问这个表,就需要等到前一个事务释放了才能对该表进行访问

行锁:

  • 它是指上锁的时候,锁住的是表的某一行或者是多行记录。
  • 就是其他的事务访问同一张表的时候,只有被锁住的记录不能够访问之外,其余的都是可以正常访问的。

        其实就是行锁就是锁住了一张表中的一条或者是多条行记录,就是其他事务要访问同一张表的时候,只有被锁的行不能够被访问外,其他的都是可以正常访问的

记录锁(Record Lock):

  • 它是属于行锁的一种,只不过记录锁的范围只是在表中的某一条记录当中。
  • 记录锁的意思是在加锁之后,锁住的只是表的某一条记录。
  • 加了记录锁之后,数据可以避免在查询的时候被修改的重复读问题。也避免了在修改的事务未提交之前被其他事务读取的脏读问题。

        其实它是行锁的一种,只不过行锁是锁的行,但是记录表锁的是行里面的某一条记录。它可以避免一些脏读和重复读的问题

页级锁:

  • 它是MySQL中锁定粒子在行级锁和表级锁中间的一种锁。
  • 因为表级锁速度很快,但是冲突很多。行级锁冲突少,但是速度慢。
  • 所以取了中间的页级锁,一次锁定相邻的一组记录。
  • 特点:开销和加锁的时间介于表锁和行锁之间。会出现死锁现象。锁定粒度介于表锁和行锁之间。

        其实它是一个介于行锁和表锁之间的一种锁。因为表锁的速度比较快但是冲突多,而行锁的冲突少但是速度又太慢。所以就会有了页级锁。它只是锁一次相邻的一组记录。它的话可能会出现死锁现象。

间隙锁(Gap Lock):

  • 它是属于行锁的一种。
  • 间隙锁是在事务加锁后其锁住的是表记录的某一个区间。
  • 当表的相邻ID之间出现空隙就会形成一个区间,遵循左开右闭的原则。
  • 范围查询并且查询未命中的记录,查询条件必须命中索引。
  • 间隙锁只会出现在repeattable_race的事务级别中
  • 触发条例:防止幻读问题。
  • 比如表里的数据id为1,4,5,7,10,那么会形成以下几个间隙区间,-n-1区间,1-4区间,4-5区间、5-7区间、7-10区间,10-n区间(-n代表负无穷大,n代表正无穷大)

        其实它就是行锁中的一种,他是锁住表记录的某一个区间。就是表的相邻ID之间会有空隙出现一个区间。然后要遵守左开右闭原则。他只会出现在repeattable_race的事务级别中

临建表(next-key lock):

  • 它也是属于行锁的一种,并且它是INNODB的行锁默认算法。
  • 总结来说,它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住。同时也会把该范围查询内的所有间隙空间也会锁住。然后它会把相邻的下一个区间也会锁住。
  • 触发条例:范围查询并且命中,查询命中了索引
  • 结合记录锁和间隙锁的特性,临建锁避免了在范围查询的时候出现的脏读、重复读、幻读的问题。
  • 在加了临键锁之后,在范围区间内数据不允许被修改和插入

        其实他也是行锁的一种他是innodb的默认算法。它其实就是记录锁和间隙锁的组合。它会把查询出来的记录锁住。同时也会把该范围查询内的所有空间也锁住。还会把相邻的下一个区间也锁住。这样就可以避免在范围查询的时候出现脏读、重复读、幻读的问题了。

意向锁是什么呢:

  1. 就是如果当事务A加锁成功之后,就会设置一个状态告诉后面的人,已经有人对表里的行加了一个排他锁了
  2. 你们不能够对整个表加共享锁或者是排它锁了
  3. 那么后面需要去做对整个表进行加锁操作的那个负责人就只需要获取这个状态就知道自己是不是可以对表进行加锁操作
  4. 避免了对整个索引树的每个节点去扫描是否加锁
  5. 而这个状态其实就是意向锁

意向共享锁:

  • 就是当一个事务视图去对整个表进行加共享锁操作之前,首先需要获得这个表的意向共享锁。

意向排他锁:

  • 就是当一个事务视图去对整个表进行加排它锁操作之前,首先需要获得这个表的意向排他锁。


7、InnoDB存储引擎的锁的算法

  • (记录锁)record lock :单个行记录上的锁
  • (间隙锁)gap lock : 锁定一个范围,不包括记录本身
  • (临建表)next-key lock: 就是record+gap锁定一个范围,包括记录本身

例子:

  1. InnoDB对于行的查询使用(临建表)next-key lock
  2. next-locking keying为了解决phantom Promble幻读问题


8、关心过业务系统里面的sql耗时问题嘛?统计过慢查询嘛?对于慢查询都是怎么优化过度的?

  • 我们在做业务系统中,除了使用主键进行的查询,其他的都会在测试库上测试其耗时问题。
  • 慢查询的统计主要是由运维在做的,就是会定期将业务中的慢查询反馈给我们。

慢查询的优化首先我们要搞明白原因是什么?是查询条件没有命中索引?还是装载了不需要数据列?还是数据量太大?

所以优化也是针对这三个方向来进行的:

  • 首先我们要先分析语句,看看是否装载了额外的数据。可能是查询了多余的行并且被抛弃掉了。也可能是加载了许多结果中并不重要的的列,对于语句进行分析以及重写
  • 再分析语句的执行计划,然后获得其使用索引的情况。之后修改语句或者是修改索引,使得语句可以尽可能的命中索引。
  • 如果已经到了语言优化无法进行的步骤的时候,可以考虑从表中的数据量是否太大,如果是的话就可以进行横向或者纵向的分表。

其实简单点就是:

  1. 先分析sql语句,看看是否加载了不需要的数据列
  2. 然后分析sql执行计划,看看字段有没有索引,索引有没有失效,有没有用对了索引
  3. 最后查看表中数据是不是会太大,看看是不是要分库分表操作


9、事务的基本特性和隔离级别

        事务的基本特性是ACID

  • 原子性:一个事务内的操作统一成功或者是失败
  • 一致性:事务前后的数据总量不变
  • 隔离性:事务和事务之间相互不影响
  • 持久性:事务一旦提交的改变是不可逆的

InnoDB默认的隔离级别为可重复读级别,分为快照读和当前读。并且通过间隙解决了幻读的问题。

(A)原子性:

  • 指的是一个事务的操作要么都成功,要么都失败

(C)一致性:

  • 指的是数据库总是一个一致性的状态转换到另一个一致性的状态。

        比如A转账给B 100块。假设A只有90块。支付之前我们数据库里的数据都是符合约束的,但是如果事务执行成功的话,我们的数据库的数据就会被破坏约束,因此事务不能成功,这里我们说事务提供了一致性的保证。

(I)隔离性:

  • 指的是一个事务的修改在最终提交前,对其他的事务是不可见的     

(D)持久性:

  • 指的是一旦事务提交,所做的修改就会被永久保存在数据库中

隔离性有四个级别

在高并发的情况下,并发事务会产生脏读、不可重复读、幻读问题,这个时候就需要用隔离级别来控制

read uncommit(读未提交):

  • 已读但是未提交,可能会读到其他的事务未提交的数据,也叫做脏读。
  • 用户本来应该读取到id=1的用户 age应该是10,结果读取到了其他的事务还没有提交的事务,就有可能会都成结果age=20,这个就是脏读

其实就是允许一个事务读取到另一个事务已提交的数据,可能会出现不可重复读和幻读。

read commit(读并提交):

  • 已读并且已经提交,两次读取的结果不一致,叫做不可重复读。
  • 不可重复读解决了脏读的问题,它只会读取到已经提交的事务。
  • 用户开启事务读取id=1的用户的时候,查询到age=10,再次读取发现结果=20。在同一个事务里,同一个查询读取到不同的结果叫做不可重复读

其实就是只允许事务读取另一个事务没有提交的数据可能会出现不可重复读和幻读。

repeatable read(可重复读):

  • 这就是mysql的默认级别,就是每次读取到的结果都是一样的,但是有可能产生幻读

其实就是确保同一个字段多次读取结果是一致的,可能会出现幻读。

serializable(串行 理解就好):

  • 串行,一般是不会去使用它的。
  • 它其实会给每一行读取的数据加锁,会导致大量超时间和锁竞争的问题。

其实就是所有事务逐次执行,没有并发问题

脏读(Dirty Read):

        某个事务已经更新了一份数据,另一个事务在此时读取了同一份数据。由于某些原因,前一个RollBack的操作,则后一个事务所读取的数据就会是不正确的

不可重复读(Non-repeatable read):

        在一个事务的两次查询之中,数据是不一致的。这可能是两次查询过程中间插入了一个事务,更新了原有的数据

幻读(Phantom Read):

  • 在一个事务的两次查询之中如果数据不一致。
  • 例如有一个事务查询了几行数据,而另一个事务却在此时插入了新的几行数据。先前的事务在接下来的查询中,就会发现有几行数据是它先前所没有的。


10、ACID靠什么保证呢? 

                

  • A 指的是原子性,它是由undolog日志保证的。它记录了需要回滚的日志信息,事务回滚的时候撤销已经执行成功的sql语句
  • C 指的是一致性,它是由其他三大特性保证的,程序代码要保证业务上的一致性,是事务的目的
  • I 指的是隔离性,它是由MVCC来保证的。
  • D 指的是持久性,它是由redo log来保证的。mysql修改数据的同时在内存和redolog记录这次操作。若有好的时机就可以从redolog中恢复过来(redolog的刷盘会在系统空闲时间去进行)


11、什么是MVCC

        MVCC其实就是多版本并发控制,为每次事务生成一个新版本的数据。每个事务都是有自己的版本的,从而不加锁就会产生读写冲突,这种叫做快照读。只在读已提交(read commit)和可重复度(repeattable read)中生效 

      

实现原理是由四个东西保证的:

  • undolog:记录了数据历史版本
  • readView:事务进行快照读的时候产生的视图,记录了当前系统中活跃的事务id,控制哪个历史版本对当前事务的可见性。
  • 隐藏字段DB_TRC_ID:最近修改记录的事务id
  • 隐藏字段:DB_Roll_PTR:回滚指针,配合undolog指向数据的上一个版本        

多版本并发控制:

  • 读取数据的时候,通过一种类似快照的方式将数据保存下来。
  • 这样共享锁和排他锁就不会发生冲突了。
  • 不同的事务session可以看到自己特定版本数据和版本链

  • MVCC只在read committed(不可重复读)和repeatable read(可重复读) 两个隔离级别下工作。
  • 其他的隔离级别和MVCC不兼容。
  • 因为read uncommitted总是读取到最新的数据行,而不是符合当前事务版本的数据行。而serializable则对所有的行都加锁

聚簇索引记录中有两个必要的隐藏列:

  • trx_id:它是用来存储每次对某条聚簇索引记录进行修改的时候的事务id
  • roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入到undo日志中。这个roll_pointer就是存了一个指针。它指向这条聚簇索引记录的上一个版本的位置。通过它来获得上一个版本的记录信息。

已提交读和可重复读的区别就在于它们生成的readview的策略是不同的。

    

  1. 开始事务的时候创建readview。
  2. 当readview维护当前活动的事务id的时候,其实就是未提交的事务id的时候,排序会生成一个数组来访问数据。
  3. 获取数据中的事务id,然后对比readview:

        其实就是事务开始的时候会创建readview,然后readview维护未提交事务id的时候,会生成一个数组来访问数据。我们要获取数据中的事务id,然后去对比readview

  • 如果在readview的左边,就是比readview小的,就可以访问(其实在左边就是意味着该事务已经提交了)
  • 如果在readview的右边,就是比readview大的或者就在readview中,就是不可以访问。获取roll_pointer,取上一版本重新对比(在右边意味着,该事务在readview生成之后出现,在readview中意味着该事务还未提交)

        其实readview的左边就是比readview小可以访问,右边就是比readview大,不可以访问。如果要获取roll_pointer,就要取上一个版本重新对比

        已经提交读隔离级别下的事务,在每次查询的开始都会生产一个独立的readview。而可重复读隔离级别则会在第一次读的时候生成一个readview,之后的读都复用了之前的readview。这个就是Mysql的mvcc。通过版本链,去实现多版本,可并发读-写,写-读。通过readview生成不同的策略实现不同的隔离级别。


12、分表后非sharding_key的查询怎么样处理,分表后的排序?

        

(1)可以先做一个mapping表

  • 比如这个时候商家要查询订单列表怎么办呢?如果不带user_id查询的话,你总不可能会去做扫描全表吧。
  • 所以我们就要去做一个映射关系表,保存商家和用户的关系。查询的时候先通过商家查询到用户列表,再通过user_id去查询。

(2)宽表,对数据实时性要求不是很高的场景。

  • 比如查询订单列表,可以把订单表同步到离线数仓,再基于数仓去做一个宽表,再基于其他如es去提供查询服务。

(3)数据量不是很大的话

  • 比如后台的一些查询之类的,也可以通过多线程去扫描表。然后再聚合结果的方法来做或者使用异步的形式也是可以的。

union

排序字段是唯一的索引:

  1. 首先第一页的查询:就是将各个表的结果集进行合并操作,然后再次进行排序
  2. 第二页以及后面的查询,需要传入上一页排序的字段的最后一个值和排序方式
  3. 根据排序方式和这个值去进行查询操作
  4. 比如排序字段date,上一页的最后值为3,排序方式为降序。查询的sql为 select...from table where data desc limt 0,10。
  5. 这样再将几个表的结果合并排序即可

        其实简单点说就是我们首先对第一个进行查询,将各个表的结果集进行合并操作,然后在对它进行排序。然后第二页以及后面的查询就需要传入上一页排序的字段的最后一个值和排序方式。根据排序方式和这个值去进行查询操作。就比如排序字段为date 上一页的最后值为3 排序方式为降序。则查询的sql语句就是select ....form table where data desc limt (0,10)


13、mysql主从同步原理

mysql的主从同步的过程

mysql的主从复制主要有三个线程:

  • master(binlog dump thread)
  • slave(i/o thread、Sql thread)
  • master一条线程和slave中的两条线程

  1. 它的主节点是binlog,主从复制的基础是主库中记录的数据库的所有变更记录到binlog中。binlog是数据库服务器启动的那一刻起,保存所有修改数据库结构或内容的一个文件
  2. 它的主节点log dump线程。当binlog有变动的时候,log dump线程读取到它的内容并发送给从节点。
  3. 从节点的I/O线程接收到binlog内容,然后将其写入到relay log文件中
  4. 从节点的sql线程读取到relay log文件内容对数据更新进行重放处理,最终保证主从数据库的一致性。

        其实就是它的一个主节点叫binlog。它是数据库服务器开启的那一刻,保存所有修改数据库结构或内容的一个文件。主从复制的基础其实就是主库中记录的数据库所有变更的记录保存到binlog当中。它还有个主节点叫log dump线程。就是当binlog有变动的时候,log dump线程就会读取到它的内容并发送给从节点。从节点又有2个,一个是i/o线程,另外一个是sql线程。i/o线程接收到binlog内容的话,就会将其写入relay log文件中。sql线程读就会去取relay log文件的内容然后对数据更新进行一个重放的处理。

注意:

  1. 主从节点使用binlog文件➕position偏移量来定位主从同步的位置。
  2. 从节点会保存已经接收到的偏移量。
  3. 如果从节点发生重启,则会自动从position的位置发起同步。

        由于mysql的默认复制方式是异步的,主库就会把日志发送给从库,但是发完之后不会去关心从库是否已经处理。这样会产生一个问题,就是假设主库挂了,从库处理失败了,这个时候从库升为主库之后,日志就会丢失。由此产生了两个概念。

全同步复制:

  • 主库写入binlog后强制同步日志到从库中,所有的从库都执行完成后才会返回给客户端但是很显然这个方式的话性能会受到严重影响。

半同步复制:

  • 和全同步不同的是,半同步复制的逻辑是这样的。就是当从库写入日志成功后,返回ACK确认给主库。主库收到至少一个从库的确认就认为写操作完成。

其实同步和半同步的区别就是同步需要所有的从库执行完成之后才返回给客户端,而半同步只需要一个从库确认就完成操作


14、简述下MyISAM和InnoDB的区别

  • InnoDB支持事务,MyIAm不支持
  • InnoDB支持外键,MyIAm不支持
  • InnoDB是聚簇索引,MyIAm是非聚簇索引
  • InnoDB是支持行锁和表锁,MyIAm只支持表锁
  • InnoDB不支持全文索引,MyIAm支持
  • InnoDB支持自增和MVCC模式的读写,MyIAm不支持

MyISAM:

  • 它是不支持事务,但是每次查询都是原子的
  • 它是支持表级锁,每次操作都是对整个表进行加锁操作
  • 它会存储表的总行数
  • 一个MyISAM表中有三个文件:索引文件,表结构文件,数据文件
  • 采用非聚集的索引,索引文件的数据域存储指向的是数据文件的指针。辅索引与主索引基本一致,但是辅索引不能保证唯一性。        

InnoDB:

  • 它支持ACID的事务,支持事务的四种隔离级别;
  • 它支持行级锁以及外键约束,因此可以支持读写和并发操作;
  • 它不存储表的总行数
  • 一个InnoDB引擎存储在一个或者是多个文件空间中,它会受到系统文件大小的限制

  • 主键索引采用的是聚集索引(也就是索引的数据域存储在数据文件本身),辅索引的数据域存储在主键的值当中。
  • 因此从辅索引中查找数据,需要先通过辅索引找到主键值,然后再次访问辅索引
  • 最好使用自增的主键,防止插入数据的时候,为了维持B+树的结构,文件需要做大调整


15、简述下mysql中索引类型及对数据库的性能的影响

普通索引:

  • 允许被索引的数据列包含重复的值

其实简单点就是允许出现重复值

唯一索引:

  • 可以保证数据记录的唯一性

其实就是唯一索引不能有相同值,但允许为空

主键索引:

  • 是一种特殊的唯一索引,在一张表中只能定义一个主键索引。主键用来唯一标识一条记录,使用关键字primary key来创建

其实就是一张表只能有一个主键索引,主键索引不能有空值和重复值

联合索引:

  • 索引是可以覆盖多个数据列,比如像index(column A,column B)索引

组合索引:

  • 对多个字段建立一个联合索引,减少索引开销,遵循最左匹配原则

全文索引:

  • 通过倒排索引的方式可以极大的提升检索的效率,解决判断字段是否包含的问题。是目前搜索引擎使用的一个关键技术。
  • 可以通过alter table table_name add fulltext(column)创建全文索引

其实就是myisam引擎支持,通过建立倒排序索引提升检索效率,广泛用于搜索引擎

  • 索引可以极大的提高了数据的查询速度
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能
  • 但是会降低插入、删除、更新表的速度,因为在执行这些写操作的时候,还需要操作索引文件
  • 索引,它是需要占据物理空间的。除了数据表占数据空间外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么就需要的空间就会更大。如果非聚簇很多的话,一旦聚集索引改变,那么所有的非聚集索引都会跟着变        

        其实就是索引可以提高数据查询速度。通过它能够在查询过程中使用优化隐藏器来提高系统性能。但是会对表的增删查改的速度会降低,因为在使用这些写操作的时候,还需要用到操作索引的文件。它还会占物理空间。就比如除了数据表占数据空间外,每一个索引还要占据一部分的物理空间。如果要建立聚簇索引的话,就需要的空间会特别大。如果是非聚簇的话,一但聚集索引发生变化,那么所有的非聚集索引都会跟着改变。


16、mysql的执行计划

SQL编写顺序:        

  • select distinct 显示字段
  • form 表名
  • join 要连接的表明 on 连接查询的条件
  • where 约束条件
  • group by 分组字段 having 分组过滤条件
  • order By AESC(降序)或者ASC(默认升序)
  • limit 分页

SQL执行的优先级:

  • from 表名
  • on 连接查询条件
  • join 要连接的表名
  • where 约束条件
  • group by 分组内容
  • having 过滤条件
  • select 显示字段
  • distinct 去重字段
  • order By AESC(降序)或者ASC(升序)
  • limit 分页

  • 其实执行计划就是sql的执行查询的顺序,以及如何去使用索引查询,返回结果集的行数。
  • explain select * from A where X = ?and Y = ?

(1)id:

  • 是一个有顺序的查询编号
  • 有几个select就会显示几行。id的顺序是按照select的出现的顺序增长的。
  • id列的值越大,执行优先级就会越高就会越先执行。
  • id列的值相同则会从上往下执行,id列的值为null就会最后执行。

(2)selectType:

  • 表示查询中每个select子句的类型

  • simple:表示查询不包含union查询或子查询
  • primary:表示此查询是最外层的查询(包含子查询)
  • subquery:子查询中的第一个select
  • union:表示此查询是union的第二或随后的查询
  • dependent union:union中的第二个或者后面的查询语句,取决于外面的查询
  • union result,union的结果
  • dependent subouery:子查询中的第一个 select,取决于外面的查询,即子查询依赖于外层查询的结果
  • derived:衍生,表示导出表的select(from子句的子查询)

(3)table:

  • 表示该语句查询的表

(4)type:

  • 优化sql的重要字段,也就是我们判断sql性能和优化程度重要指标。

它的取值范围类型:

  • const:通过索引一次命中,匹配一行数据
  • system:表中只有一行记录,相当于系统表
  • eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配
  • ref:非唯一性索扫描,返回匹配某个值的所有
  • range:只检索给定范围的行,使用一个索引来选择行,一般用于between、<、>
  • index:只遍历索引树;
  • All:表示全表扫描,这个类型的查询是性能最差的查询之一。那么基本就是随着表的数量增多,执行效率越慢

执行效率:

  • all < index < range < ref < eq_ref < const < system
  • 最好避免all和index

(5)possible_key:

  • 它是表示mysql在执行该sql语句的时候,可能用到的索引信息,仅仅是可能,实际不一定会用的到

(6)key:

  • 这个字段是mysql在当前查询的时候所真正使用到的索引。它是possible_keys的子集

(7)key_len:

  • 表示查询优化器使用了索引的字节数,这个字段可以评估组合索引是否完全被使用。
  • 这也是我们优化sql的时候,评估索引的重要指标。

(8)rows:

  • mysql查询优化器根据统计的信息,估计sql的返回结果集需要扫描读取的行数,这个值就相当重要的。
  • 索引优化之后,扫描读取的行数越多,说明索引设置的不对,或者是字段传入的类型之类的问题。这说明要优化的空间很大

(9)filtered:

  • 返回结果的行占需要读到行(rows列的值)的百分比
  • 就是百分比越高,说明需要查询到的数据越准确
  • 百分比越小,说明查询到的数据量大,而结果集很少

(10)extra:

  • using filesort:表示mysql对结果集进行外部排序,不能通过索引顺序达到排序的效果。一般有using filesort都建议优化去掉,因为这样的查询cpu资源消耗大,延时长。
  • using index:覆盖索引扫描,表示查询在索引树中就可以查找到所需的数据,不用扫描数据文件,往往说明性能不错
  • using temporary:查询有使用临时表,一般出现于排序,分组和多表join的情况,查询效率不高,建议优化
  • using where:sql使用where过滤,效率较高     

      


17、什么是快照读和当前读

  • 快照读读取的是当前数据的可见版本,可能是会过期的数据,不加锁的select都是快照读。
  • 当读取的是数据的最新版本的时候,当前读返回的记录都会被上锁,保证了其他的事务不会并发修改这条记录。
  • 比如update、insert、delete、select for undate(排他锁)、select lockin share mode(共享锁)这些都是当前读。        

其实快照读就是读取当前数据的课件版本,当前读读取的是数据的最新版本。


18、B树和B+树有什么区别,为什么会使用B+树

  • 二叉树:其实就是索引字段有序,极端情况会变成链表的形式
  • AVL树:其实就是树的高度不可控制
  • B树:其实就是控制了树的高度,但是索引值和data都分部在每个具体的节点当中。如果要进行范围查询的话,要进行多次回溯,IO开销会很大
  • B+树:非叶子节点只存在存储索引的值,叶子节点再存储索引➕具体数据。从小到大用链表连接在一起,范围查询可直接遍历,不需要回溯。



19、哪些情况索引会失效

(1)where条件中有or,除非所有的查询条件都有索引,否则就会失败

(2)like查询用%开头,索引就会失效

(3)索引列参与计算,索引就会失效

(4)违背最左匹配原则,索引就会失效

(5)索引字段发生类型转换,索引就会失效

(6)mysql觉得全表扫描更快的时候,索引就会失效    


20、MySQL内连接、左连接、右连接的区别

  • 内连接(inner join)取表的交际部分
  • 左连接(left join)取左表全部➕右表匹配部分
  • 右连接(right join)取右表全部➕左表匹配部分

        其实简单点就是内连接是左连接和右连接结合拼接起来的,左连接就是左边全部➕右边匹配,没有的话就是null。右连接就是右边全部➕左边匹配,没有的就是null


21、如何设计数据库

(1)抽取实体,如用户信息,商品信息,评论等等

(2)分析其中的属性,如用户信息:姓名,学号,年龄,职业规划等等

(3)分析表与表之间的关联关系(比如一对多,多对一,多对多)


22、where和having的区别

  • where是约束声明,having是过滤声明
  • where早于having执行,并且where不可以使用聚合函数,having可以使用聚合函数


23、char和varchar区别

  • char是不可变的,最大长度为255
  • varchar是可变的字符串,最大长度在2的16次方


24、InnoDB什么情况下会产生死锁

  • 事务1已经获得了数据A的写锁,想要去获取数据B的写锁。然后事务2获取了B的写锁,想要去获取A的写锁,相互等待形成了死锁。

mysql解决死锁的机制有两个:

  1. 等待,直到超时
  2. 发起死锁检测,主动回滚一条事务

死锁的检测原理:

  • 其实就是构建一个以事务为顶点,锁为边的有向图。判断有向图是否存在环,如果有存在环就会有死锁。

我们平时尽量减少事务操作的资源和隔离级别


25、MySQL删除自增id,随后重启MySQL服务,再插入数据,自增id会从几开始

InnoDB引擎:

  • MySQL8.0前,下次自增会取表中最大 id + 1。原理是最大的id会记录在内存当中,重启之后会重新读取表中最大的id
  • MySQL8.0后,仍然是从删除数据id后开始算起。它的原理是将最大id记录在redolog当中

MyISAM:

  • 自增的id都从删除数据id后算起。它的原理是将最大id记录到数据文件里

猜你喜欢

转载自blog.csdn.net/qq_46423017/article/details/127339247
m y
S&Q