当前位置: 首页 > news >正文

MySql复习及面试题学习

资源来自于竹子爱熊猫、小林coding、沉默王二、javaguide

二、面试题

什么是mysql?nosql和sql的区别说说?

MySQL 是一个开源的关系型数据库,存储数据通常是以一种二维表的方式存在,它与redis不同,redis是一种非关系型数据库,是以哈希表的方式存储数据的。

而关系型数据库和非关系型数据库也不一样,关系型数据库支持事务的acid属性,而非关系型数据库一般都不支持,不过他们在扩展性上面做了补充,比如redis的主从复制模式、哨兵模式、切片集群模式,而关系型数据库扩展性较差,存在分布式事务的问题。

数据库的连表查询怎么查?

数据库有以下几种联表查询类型:

内连接 (INNER JOIN):内连接返回两个表中有匹配关系的行

左外连接 (LEFT JOIN):左外连接返回左表中的所有行,即使在右表中没有匹配的行。未匹配的右表列会包含NULL

右外连接 (RIGHT JOIN):右外连接返回右表中的所有行,即使左表中没有匹配的行。未匹配的左表列会包含NULL

全外连接 (FULL JOIN):相当于左外连接和右外连接的并集

数据库的三大范式是什么?

第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。

第二范式(2NF):非主键属性必须完全依赖于主键,不能只与主键的部分列相关。

第三范式,非主键列应该只依赖于主键列,消除传递依赖。

其实三大范式实质上是为了消除数据冗余、异常问题,只要满足这三个要求就能实现一个基本合格的数据库。

第一范式还是很基本的,这样我们在查数据的时候也很方便,比如一个列包含了多种原子性数据,那我要是只需要一个还得对数据做处理,显然得不偿失。

而第二范式也能理解,如果只根据主键中的部分列获取数据的话,如果不满足第二范式,我们还得去重,而且数据库表中有大量空间都浪费去存冗余的数据,浪费资源

而第三范式跟第二范式有点类似,根据非主键获取数据也可能要去重,这样也浪费了表空间,消耗资源。

varchar与char的区别?

CHAR是固定长度的字符串类型,定义时需要指定固定长度,存储时会在末尾补足空格。CHAR适合存储长度固定的数据,如固定长度的代码、状态等,存储空间固定,对于短字符串效率较高。

VARCHAR是可变长度的字符串类型,定义时需要指定最大长度,实际存储时根据实际长度占用存储空间。VARCHAR适合存储长度可变的数据,如用户输入的文本、备注等,节约存储空间。

括号里的数字代表字符数量

blob和text有什么区别,text可以无限大吗?

blob 用于存储二进制数据,比如图片、音视频等;但实际开发中,我们都会把这些文件存储到 OSS 或者文件服务器上,然后在数据库中存储文件的 URL。

text 用于存储文本数据,比如文章、评论、日志等。text存储的数据最大能达到64kb,如果还想大的话可以使用longtext,最大能达到4GB

datetime和timestamp区别?

DATETIME 直接存储日期和时间的完整值,与时区无关。

TIMESTAMP 存储的是 Unix 时间戳,1970-01-01 00:00:01 UTC 以来的秒数,受时区影响。

另外,DATETIME 的默认值为 null,占用 8 个字节;TIMESTAMP 的默认值为当前时间——CURRENT_TIMESTAMP,占 4 个字节,实际开发中更常用,因为可以自动更新

in 和exists的区别?

1、当使用 IN 时,MySQL 会首先执行子查询,然后将子查询的结果集用于外部查询的条件。这意味着子查询的结果集需要全部加载到内存中。

而 EXISTS 会对外部查询的每一行,执行一次子查询。如果子查询返回任何行,则 EXISTS 条件为真。EXISTS 关注的是子查询是否返回行,而不是返回的具体值。

2、IN 适用于子查询结果集较小的情况。如果子查询返回大量数据,IN 的性能可能会下降,因为它需要将整个结果集加载到内存。

而 EXISTS 适用于子查询结果集可能很大的情况。由于 EXISTS 只需要判断子查询是否返回行,而不需要加载整个结果集,因此在某些情况下性能更好。

3、关于null值的处理,in里面如果有null那很可能在where里会出现未知的结果,所查询的最终数据可能出乎意料。而exists不会,它只会判断是否存在,而返回true或false,不关注具体值。

(‘张三’=NULL的结果为unknown,null=null的结果也为unknown,这就导致结果跟预计不一样)

drop、truncate、delete的区别

DROP 是物理删除,用来删除整张表,包括表结构,且不能回滚。

TRUNCATE 用于清空表中的所有数据,但会保留表结构,不能回滚。

DELETE 支持行级删除,可以带 WHERE 条件,而且会记录binlog日志,可以回滚

count(1)、count(*) 与 count(列名) 的区别?

  • 在 InnoDB 引擎中,COUNT(1) 和 COUNT(*) 没有区别,都是用来统计所有行,包括 NULL,而且会优先使用索引。
  • COUNT(列名) 只统计列名不为 NULL 的行数,而且优先使用列所在的索引,没有索引则进行全表扫描。而且扫描时会读取记录的字段值,判断是否为null,所以效率低一点

sql语句的执行顺序了解吗?

先执行 FROM 确定主表,再执行 JOIN 连接,然后 WHERE 进行过滤,接着 GROUP BY 进行分组,HAVING 过滤聚合结果,SELECT 选择最终列,ORDER BY 排序,最后 LIMIT 限制返回行数。
FROM确定主表,准备数据
ON连接多个表的条件
JOIN执行 INNER JOIN / LEFT JOIN 等
WHERE过滤行数据(提高效率)
GROUP BY进行分组
HAVING过滤聚合后的数据
SELECT选择最终返回的列
DISTINCT进行去重
ORDER BY对最终结果排序
LIMIT限制返回行数

常用sql命令

常用函数

mysql的架构是怎么样的?

连接层主要负责客户端连接的管理,包括验证用户身份校验、连接管理等。可以通过数据库连接池来提升连接的处理效率。

服务层是 MySQL 的核心,主要负责查询解析、优化、执行等操作。在这一层,SQL 语句会经过解析、优化器优化,然后转发到存储引擎执行,并返回结果。这一层包含查询解析器、优化器、执行计划生成器、日志模块等。

存储引擎层负责数据的实际存储和提取。MySQL 支持多种存储引擎,如 InnoDB、MyISAM、Memory 等。

一条查询sql语句的执行流程

首先客户端编写Sql语句,发起网络请求获取数据库连接池对象(这里使用TCP协议)这里双方各维护一个连接池,数据库是连接器在进行连接的建立与管理。

然后真正开始处理sql,先去查询缓存(8.0后删除了缓存),缓存以 key-value 形式保存在内存中的,key 为 SQL 查询语句,value 为 SQL 语句查询的结果。若缓存中存在该语句的结果则返回给客户端。

如果没有则将sql语句交给解析器,判断是否符合sql语法规范。解析完成后会生成语法树

然后开始执行sql,先会进行预处理,检查表和字段是否存在

然后优化器会根据语法树生成多条解决方案然后选择一个最好的计划交给线程去执行。

最后执行器会进行调用对应存储引擎的api,存储引擎去硬盘中查数据发生磁盘io。返回给客户端

一条更新语句是如何执行的?(结合日志)

  • 客户端先获取数据库连接池对象,将SQL发送给SQL接口
  • 然后会在缓存中根据哈希值检索数据,将对应表的所有缓存全部删除。
  • 如果没有则将sql语句交给解析器,判断是否符合sql语法规范。解析完成后会生成语法树,再进行预处理,判断字段是否存在
  • 接着优化器根据SQL制定出不同的执行方案,并择选出最优的执行计划。
  • 在执行开始之前,先记录一下undolog日志和redo-log(prepare状态)日志。
  • 接着在缓冲区中查找是否存在当前要操作的行记录或表数据(内存中):
    • 存在:
      • 直接对缓冲区中的数据进行写操作。然后利用Checkpoint机制刷写到磁盘。
    • 不存在:
      • 磁盘加载数据页到Buffer Pool,然后在内存中修改
  • 写操作完成后,记录bin-log日志,同时将redo-log日志中的记录改为commit状态。
  • SQL执行的结果返回给SQL接口,再由SQL接口返回给客户端。

mysql的段区页行了解吗?

①、段:表空间由多个段组成,常见的段有数据段、索引段、回滚段等。

创建索引时会创建两个段,数据段和索引段,数据段用来存储叶子节点中的数据;索引段用来存储非叶子节点的数据。

回滚段包含了事务执行过程中用于数据回滚的旧数据。

②、区:段由一个或多个区组成,区是一组连续的页,通常包含 64 个连续的页,也就是 1M 的数据。

使用区代替页进行数据分配可以优化磁盘操作,减少磁盘寻道时间

③、页:页是 InnoDB 存储数据的基本单元,标准大小为 16 KB,索引树上的一个节点就是一个页。

也就意味着数据库每次读写都是以 16 KB 为单位的,一次最少从磁盘中读取 16KB 的数据到内存,一次最少写入 16KB 的数据到磁盘。

④、行:InnoDB 采用行存储方式,意味着数据按照行进行组织和管理,行数据可能有多个格式,比如说 COMPACT、DYNAMIC 等。

一行数据通常包括变长字段长度列表、NULL 值列表、记录头信息以及数据部分

变长字段长度列表存varchar的实际大小,其中的信息会逆序存放,从而提高 CPU Cache 的命中率。

null值列表是逆序存放哪些列为null的,用1或0表示

mysql支持哪些存储引擎?

主要支持三种存储引擎,innodb\memory\myisamo\

InnoDB:InnoDB是MySQL的默认存储引擎,具有ACID事务支持、行级锁、外键约束等特性。它适用于高并发的读写操作,支持较好的数据完整性和并发控制。

MyISAM:MyISAM是MySQL的另一种常见的存储引擎,具有较低的存储空间和内存消耗,适用于大量读操作的场景。不过MyISAM不支持事务、行级锁和外键约束,因此在并发写入和数据完整性方面有一定的限制。

Memory:Memory引擎将数据存储在内存中,适用于对性能要求较高的读操作,但是在服务器重启或崩溃时数据会丢失。它也不支持事务、行级锁和外键约束

innodb和myisam有什么区别?

事务:InnoDB 支持事务,MyISAM 不支持事务,因为innodb有特有的undolog\redolog日志,支持崩溃恢复和事务回滚,这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一。

索引结构:InnoDB 是聚簇索引,MyISAM 是非聚簇索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。而 MyISAM 是非聚簇索引,数据文件是分离的,索引保存的是数据文件的指针。索引走二级索引时不需要回表。

锁粒度:InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。

count 的效率:InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快。

索引是什么?有什么好处?为什么用了索引会快?

 索引其实就是数据的目录,与全表扫描相比能方便我们更快的去查数据。

如果查询的时候,没有用到索引就会全表扫描,这时候查询的时间复杂度是On 如果用到了索引,像mysql 索引的数据结构一般是 b+树,其搜索复杂度为O(logdN)

(其中 d 表示节点允许的最大子节点个数为 d 个,以d为底N的对数,也通常读作O(logN))

索引怎么分类的?

数据结构分:B+树索引、hash索引、全文索引。

B+树索引将所有数据存储在叶子节点,复杂度低查询快,也是Innodb存储引擎的默认索引结构

hash索引:适合等值查询,但无法高效查询范围(mysql不支持)

物理存储分:主键索引、二级索引

主键索引的 B+Tree 的叶子节点存放的是实际数据,所有完整的用户记录都存放在主键索引的 B+Tree 的叶子节点里;

二级索引的 B+Tree 的叶子节点存放的是主键值,而不是实际数据。

在查询时使用了二级索引,如果查询的数据能在二级索引里查询的到,那么就不需要回表,这个过程就是覆盖索引。如果查询的数据不在二级索引里,就会先检索二级索引,找到对应的叶子节点,获取到主键值后,然后再检索主键索引,就能查询到数据了,这个过程就是回表。

从字段特性的角度来看,索引分为主键索引、唯一索引、普通索引、前缀索引

主键索引:在主键上建立的索引

唯一索引:在unique字段上建立的索引

普通索引:对字段无要求

前缀索引:指对字符类型字段的前几个字符建立的索引

按字段个数分类:单列索引,联合索引

单列索引就是对一个列设置索引

联合索引则是对多个列设置索引,遵循最左匹配原则。联合索引的最左匹配原则,在遇到范围查询的时候就会停止匹配,也就是范围查询的字段可以用到联合索引,但是在范围查询字段的后面的字段无法用到联合索引。

创建索引要注意什么?

1、选择合适的字段:比如频繁出现再orderby\where\groupby的字段,而且字段区分度要高,不能是像性别这样区分度低的字段

2、要控制索引的数量,因为索引也要占据物理空间,所以我们不能建立太多

(可以用show     index from table_name来查看)

3、使用联合索引的时候要考虑最左匹配原则,所以我们尽量将等值查询的字段放在左侧,并最好只查询二级索引里的字段,避免回表。

索引哪些情况会失效

1、对索引列使用了函数表达式会失效

2、还有使用Like模糊查询时,以通配符开头会导致索引失效

3、然后就是联合索引,当我们使用联合索引时违背了最左匹配原则会失效

4、还有就是where子句中,使用or连接非索引列就会导致索引失效

5、还有就是等值查询时如果涉及字符串字段与数字进行比较时会失效,因为mysql会将字段转为数字,相当于使用了函数,所以会失效

什么时候适合索引,什么时候不适合?

不适合:

区分度低的字段,比如性别就不适合。还有就是频繁更新的列,如果频繁更新的列还使用索引,会导致索引频繁变化增加维护成本。还有对于数据量比较小的时候,也可以不使用索引。

适合:

主键、唯一键、以及经常作为查询条件的字段最适合加索引。除此之外,字段的区分度高的也适合,这样索引才能起到过滤作用;如果字段经常用于表连接、排序或分组,也适合加索引。同时如果多个字段经常一起出现在查询条件中,也可以建立联合索引来提升性能。

索引优化了解吗?你会怎么优化索引?

索引优化通常根据不同的索引我们采取不同的优化方式。

比如前缀索引:对于字符串字段我们可以考虑使用前缀索引代替普通索引,能有效提高索引的查询速度。

还有覆盖索引优化,我们使得要查询的字段都存储在二级索引的叶子节点里,这样的话就不会再去回表查一级索引了,也能提高效率

还有就是对于主键索引最好是自增的,这样的话插入数据都是追加操作,不用重新移动数据。如果是非自增的,每次插入新数据时可能会发生页分裂现象,导致索引树频繁修改,增加了开销。

最后就是避免索引失效,(回答索引失效的情况),所以我们在使用索引时最好避免发生。

Innodb为什么采用B+树作为索引?

 使用B+树是因为它适合范围查询,而且IO次数少。

如果使用B树的话,由于B树的非叶子节点也要存数据。所以有额外的空间开销,而且插入删除的效率要低一些,当然B树也无法做到范围查询,因为它的叶子节点没有链表来维护,而且B 树的范围查询还需要通过遍历逐层回溯,更加复杂

如果使用二叉树的话,则磁盘IO次数会太大,因为他的复杂度是OlogN,但B+树是Olog,d为每层的节点数通常大于100,甚至是一千多,这意味着哪怕是千万级别的数据也只会发生3\4次IO。

如果使用hash索引的话因为不支持范围查询,所以应用场景少。而全文索引是为文本分词设计的,对数值型或短字符串的精确查询效率低下,

如果使用红黑树的话在这种数据量下的查询次数则跟二叉树差不多,层级也会很高时间开销大

所以最适合的还是B+树作为索引。

一棵B+树能存多少条数据?

一棵 B+ 树能存多少数据,取决于它的分支因子和高度。在 InnoDB 中,页的默认大小为 16KB,当主键为 bigint 时,3 层 B+ 树通常可以存储约 2000 万条数据。

假设主键为bigint,那就是8字节。再加上4字节页号,2字节页内偏移那就是14字节。一页为16KB,也就是一页存1100多条索引,第二层仍为非叶子节点,那就又是1100多页,第三层为叶子节点,假设一条数据为1KB,那一页能存16条,最后一乘就是2000万。

什么是聚簇索引和非聚簇索引?

1、在聚簇索引中,索引的叶子节点包含了实际的数据行。非聚簇索引的叶子节点不包含完整的数据行,而是包含指向数据行的指针或主键值。而数据行本身存储在聚簇索引中。

2、聚簇索引通常是基于主键构建的,因此每个表只能有一个聚簇索引。但一个表可以有多个非聚簇索引,因为它们不直接影响数据的物理存储位置。

3、当通过聚簇索引查找数据时,可以直接从索引中获得数据行,而不需要额外的步骤去查找数据所在的位置。当通过非聚簇索引查找数据时,通常会在非聚簇索引中找到对应的主键值,然后通过这个主键值回溯到聚簇索引中查找实际的数据行,进行回表查询。

4、所以当我们可以通过覆盖索引进行查询时,非聚簇索引效率更高,因为它不需要读取完整的数据行也无需回表,而在其他情况则使用聚簇索引更好。

回表了解吗?

回表的存在主要源于聚簇索引和非聚簇索引,聚簇索引存储的是表的所有数据,而非聚簇索引只存储索引字段和主键值,当我们使用非聚簇索引时,假如要查询所有字段时通常会再去聚簇索引查一次,因为非聚簇索引不包含我们要查的所有字段,而这个过程就是回表。

联合索引了解吗?怎么实现的?

将多个字段组合成一个索引,该索引就被称为联合索引。而其实现原理就是将多个字段都设为每一条数据的key。而这些key按照字段的顺序进行排序,先按照第一个字段排序,再按第二个字段排序,以此类推。

而联合索引的这种方式也产生一个原则:最左匹配原则。也就是按照最左优先的方式进行索引的匹配。在使用联合索引进行查询的时候,如果不遵循最左匹配原则联合索引会失效,所以我们尽量避免这种情况。

覆盖索引了解吗?

覆盖索引是指一个二级索引包含了查询所需的所有列,因此不需要访问一级索引中的数据行就能完成查询,也就是不需要进行回表查询。

通常我们可以将高频查询的字段(如 WHERE 条件和 SELECT 列)组合为联合索引,实现覆盖索引。因为覆盖索引能够显著提高查询性能,因为减少了访问数据页的次数,从而减少了I/O操作。

什么是索引下推?

索引下推是指:MySQL 把 WHERE 条件尽可能“下推”到索引扫描阶段,在存储引擎层提前过滤掉不符合条件的记录。

没有索引下推的时候,每查询到一条二级索引记录,都要进行回表操作,然后将记录返回给 Server,接着 Server 再判断该记录。

而有索引下推时,先不执行回表操作,而是先判断一下该索引中包含的列的条件是否成立。如果条件不成立,则直接跳过该二级索引。如果成立则执行回表操作,将完成记录返回给 Server 层

讲一下MySql有哪些锁?

根据加锁的范围可以分为全局锁、表锁、行锁

首先是全局锁,通过flush tables with read lock 可以锁住整个数据库变成只读状态,任何增删改的操作都会被阻塞。全局锁通常发生全库逻辑备份,以免出现逻辑不一致问题。

然后就是表锁,表锁最常见的有读写锁、元数据锁、意向锁和自增锁。读写锁就是我们人为给表加读锁或写锁,读锁的话就只能共享读,写锁的话只能本线程进行读写。

而当我们对表结构做修改的时候会给表自动加上元数据写锁,这样其他线程都无法对这个表进行crud操作,而进行crud的时候就会加上元数据读锁,这样表示有线程在读表结构。

还有就是意向锁,当执行插入、更新、删除操作,需要先对表加上意向独占锁,然后对该记录加独占锁,意向共享锁也同理。意向锁的目的是为了快速判断表里是否有记录被加锁。这样别的线程来了之后能立刻知道有没有线程在操作表。

而自增锁主要就是为了表主键自增用的,在插入数据时,会加一个表级别的 自增锁,然后等插入语句执行完成后,才会把自增锁释放掉。

最后是行锁,Innodb是支持行锁的,行锁主要分为记录锁、间隙锁、临键锁。记录锁就是对一条记录上锁,而间隙锁就是对范围加锁,间隙锁主要是为了解决可重复读级别下的幻读问题,防止插入幻影记录而存在的。最后就是临键锁,临键锁就是记录锁加间隙锁,innodb的行锁通常都是直接加临键锁的。

(对于普通的select语句它是不会加行锁的,因为它是靠MVCC机制实现的,不过我们可以认为使用lock in share mode 或for update 加行级共享锁或行级独占锁,而增删改加的都是独占锁。)

MySql的乐观锁和悲观锁了解吗?

MySQL 中的行锁和表锁都是悲观锁。悲观锁是一种"先上锁再操作"的策略,它假设数据被外界访问时必然会产生冲突,因此在数据处理过程中全程加锁。

而乐观锁会假设并发操作不会总发生冲突,而是在提交更新时才检查数据是否被其他事务修改过。乐观锁并不是 MySQL 内置的锁机制,不过我们可以通过添加版本号字段的方式来实现。

Mysql死锁了解吗?怎么解决?

MySQL 的死锁是由于多个事务持有资源并相互等待引起的,事务1持有锁A想要获取锁B,事务2持有锁B想要获取锁A,这时就会出现死锁。

我们利用Innodb引擎可以有两种打破死锁的方式

一种是设置事务等待锁的超时时间。当一个事务的等待时间超过该值后,就对这个事务进行回滚,于是锁就释放了,另一个事务就可以继续执行了

另一种是开启主动死锁检测。主动死锁检测在发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行

当然我们也可以使用SHOW ENGINE INNODB STATUS 查看死锁信息来调整。

Mysql的事务特性说一下?

主要有四个,原子性、隔离性、持久性、一致性

原子性指的是一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,Innodb引擎使用undolog日志来保证原子性。

隔离性是数据库允许多个并发事务同时对其数据进行读写和修改的能力,而Innodb引擎是通过MVCC机制和锁机制来实现的

持久性是事务处理结束后,对数据的修改就是永久的不会丢失,Innodb引擎采用redolog日志来实现的

一致性是是指事务操作前和操作后,数据满足完整性约束,数据库仍然保持一致性状态。一致性的实现是通过持久性+原子性+隔离性来保证的。

事务的隔离级别有哪些?

  • 读未提交RU:事务可以读取其他未提交事务修改的数据。所以会出现脏读、不可重复读、幻读问题。
  • 读已提交RC:指一个事务提交之后,它做的变更才能被其他事务看到;解决了脏读问题,但没有解决幻读不可重复读问题
  • 可重复读RR:指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,是MySQL的默认隔离级别。解决了可重复读和大部分的幻读问题。
  • 串行化:串行化是最高的隔离级别,通过读写锁强制事务串行执行来解决“幻读”问题,不过效率通常较低。

  通常更改命令类似于SET  TRANSACTION ISOLATION LEVEL

什么是脏读、不可重复读、幻读问题?

脏读是指当前事务修改数据但还未提交事务,但是其他事务却读到了数据。

不可重复读是在一个事务内多次读取同一个数据,但是出现前后两次读到的数据不一样的情况

幻读则是在一个事务内多次查询某个符合查询条件的记录数量,但是出现前后两次查询到的记录数量不一样的情况

事务的隔离级别是如何实现的?

读未提交主要是靠行共享锁来实现的,这样多个事务之间对该记录读读共享,只要一个事务修改了但事务未提交,其他事务也能看到,所以会有脏读现象。

读已提交是通过加行级排他锁来实现修改安全的,这样在事务未提交之前其他事务都不能读写该条记录,所以解决了脏读问题。但是事务每次读数据时都重新创建一个快照,那么在事务期间的多次读取同一条数据,前后两次读的数据可能会出现不一致,因为可能这期间另外一个事务修改了该记录,并提交了事务。

可重复读则通过MVCC和临键锁来解决可重复读问题和大部分幻读问题。对于快照读,使用了MVCC机制,只在第一次查询时生成一个快照,后面每次读都是读这个快照,保证了多次读取数据一致。而针对当前读则使用临键锁来解决,凡是当前事务要查询和修改所涉及到的数据我都上锁,而且对于涉及到的范围也上锁,不让别的事务插入数据,这样前后多次读写都不会出问题。

最后是串行化,是通过加锁来实现的,其他事务都不能对当前事务涉及到的数据及范围进行增删改,避免了脏读、不可重复读、幻读问题

可重复读级别解决了所有幻读问题吗?没解决能举个例子吗?

幻读是在一个事务内多次查询某个符合查询条件的记录数量,但是出现前后两次查询到的记录数量不一样的情况,mysql在可重复读级别下使用了mvcc机制和临键锁解决了大部分问题,但仍然存在幻读现象。

举个例子事务 A 执行快照读查询 id = 5 的记录,此时表中是没有该记录的,然后事务 B 插入一条 id = 5 的记录,并且提交了事务。此时事务 A 更新 id = 5 这条记录,然后再次查询 id = 5 的记录,事务 A 就能看到事务 B 插入的纪录了,这就出现了幻读问题。

实际上这源自于事务 A 对 id = 5 这条记录进行了更新操作,在这个时这条记录的事务id就变成了事务 A 的事务 id,所以再用快照读就能查出来了

MVCC了解吗?怎么实现的?

MVCC 指的是多版本并发控制,每次修改数据时,都会生成一个新的版本,而不是直接在原有数据上进行修改。并且每个事务只能看到在它开始之前已经提交的数据版本,它的底层实现依赖于readview和undolog。

readview就是快照,它有四个重要的字段:当前事务、活跃事务id列表、最小活跃事务id、下一个可分配事务id(最大事务id+1),对于数据库表的每一条记录都包含两个隐藏列:当前事务id(6字节)和回滚指针(7字节),回滚指针指向上一个版本的记录,多个历史版本就是通过回滚指针来形成版本链的。

事务a在读一条数据时会查看事务id与自己的快照进行比对,如果是小于最小活跃事务或者为活跃事务列表中的已提交事务则该记录可见,如果超过了快照的最大事务id或者为活跃事务列表中的未提交事务则该记录不可见,根据回滚指针找上一个版本再判断。

mysql日志文件有哪些?

主要有六种:

①、错误日志:记录 MySQL 服务器启动运行时出现的问题。

②、慢查询日志:记录执行时间超过 long_query_time 的所有 SQL 语句。这个时间值是可配置的,默认情况下慢查询日志功能是关闭的。

③、一般查询日志:记录 MySQL 服务器的启动关闭信息,客户端的连接信息,以及更新、查询的 SQL 语句等。

④、binLog:记录所有修改数据库状态的 SQL 语句,以及每个语句的执行时间

⑤、redo Log:记录对于 InnoDB 表的每个写操作,主要用于崩溃恢复。

⑥、undo Log:记录数据被修改前的值,用于事务的回滚。

(中继日志,写在从库里的)

讲讲redolog、undolog、binlog

undolog是回滚日志,它保证了事务中的原子性,在事务没提交之前,MySQL 会先记录更新前的数据到 undo log 日志文件里面,当事务回滚时,可以利用 undo log 来进行回滚。

而基于undolog形成的版本链,也从而与readview共同实现了MVCC机制,MySQL 在执行快照读的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

redolog是重做日志,主要用来崩溃恢复的,会记录某个数据页做了什么修改,在事务提交时,只要先将 redo log 持久化到磁盘即可,可以不需要等到将缓存池里的脏页数据持久化到磁盘。系统崩溃时,虽然脏页数据没有持久化,但是 redo log 已经持久化,接着 MySQL 重启后可以根据 redo log 的内容,将所有数据恢复到最新的状态。

除此之外,redolog将持久化由随机写升级为了顺序写,能有效的提高性能。不过通常redolog会先写入到redolog缓存里,再由缓存写到磁盘,这样能减少io次数。这里写回时间有三种选择,第一种是提交事务时开启后台线程,它每隔一秒将日志写入内核缓冲区再写入磁盘,这种方式性能高但安全性低,数据库崩溃时会丢失一秒内的数据;第二种是事务提交时直接写入磁盘,这种方式性能低一些但安全性高;第三种则是事务提交时直接写入内核缓冲区,再每隔一秒写入到磁盘,这种性能和安全性适中,只有系统断电才会丢失一秒的数据。

除此之外,如果redolog写满了,则会阻塞mysql,因为redolog是使用循环写的方式,脏页更新后会擦除无效记录,如果写满了只能阻塞进行脏页的落盘,等腾出空间再继续,所以我们实际使用时要设置适当的redolog文件组大小减少阻塞。

binlog是server层的,记录了所有数据库表结构变更和表数据修改,主要用于主从复制。binlog 有 3 种格式类型,分别是 STATEMENT(默认格式)、ROW、 MIXED: STATEMENT:每一条修改数据的 SQL 都会被记录到 binlog 中,主从复制中 slave 端再根据 SQL 语句重现。但 STATEMENT 有动态函数的问题,比如你用了  now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,会导致复制的数据不一致;

ROW:记录行数据最终被修改成什么样了,不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,会产生很多条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已; MIXED:包含了 STATEMENT 和 ROW 模式,对于可以复制的SQL采用Statment模式记录,对于无法复制的SQL采用Row记录。

binlog的刷盘会先写入到内核缓冲区里,再进行刷盘,刷盘时机也有三种

sync_binlog = 0 的时候,表示罗盘时机交由操作系统决定;

sync_binlog = 1 的时候,表示马上执行落盘;

sync_binlog =N的时候,表示累积 N 个事务后才落盘。

为什么有了undolog还要redolog?

因为undolog是写入缓存池里的,而缓存池是基于内存的,万一断电了数据未落盘就会造成丢失,所以增加了redolog就是为了实现持久化机制的。每当开启事务进行数据的修改时都会在redolog里面写入具体操作,等到事务提交时将redolog写入磁盘。如果这时候断电了,对于已提交的事务那就说明redolog写完了,而未提交的事务的话,既然未提交就是未完成,我再进行回滚到开启时状态即可,这样就保证了数据的持久化。

为什么有了binlog还要redolog、undolog?

binlog 属于 Server 层,与存储引擎无关,无法直接操作物理数据页。而 redo log 和 undo log 是 InnoDB 存储引擎实事务的基石。

binlog 关注的是逻辑变更的全局记录;redo log 用于确保物理变更的持久性,确保事务最终能够刷盘成功;undo log 记录的是旧值,方便恢复到事务开始前的状态。他们的职责和功能都不一样。

不过实际上binlog和redolog有部分功能是类似的,都要进行持久化,但是mysql一开始的默认引擎是myisam,myisam不支持事务,所以mysql在server层实现了binlog,redolog是innodb特有的,不能说因为后面更换了引擎就不要binlog了,如果人为更换引擎总得要保证持久化吧,所以我认为server层的binlog更像一个兜底机制,保证数据持久化。

当然binlog还可以用作主从复制,也是redolog做不了的

binlog和redolog有什么区别?

  • 生效范围不同,Redo-logInnoDB专享的,Bin-log是所有引擎通用的。
  • 写入方式不同,Redo-log是用多个文件循环写,而Bin-log是不断创建新文件追加写。
  • 文件格式不同,Redo-log中记录的都是变更后的数据,而Bin-log会记录变更SQL语句。
  • 使用场景不同,Redo-log主要实现故障情况下的数据恢复,Bin-log则用于数据灾备、同步。

binlog两阶段提交了解吗?

两阶段提交主要是为了保证 redo log 和 binlog 中的数据一致性,防止主从复制和事务状态不一致。

当客户端提交事务时,MySQL 内部开启一个 XA 事务,分两阶段来完成 XA 事务的提交

首先是prepare 阶段:将 XID 写入到 redo log,同时将 redo log 对应的事务状态设置为 prepare,然后将 redo log 持久化到磁盘(默认这样,因为最安全);

接着是commit 阶段:把 XID 写入到 binlog,然后将 binlog 持久化到磁盘,接着调用引擎的提交事务接口,将 redo log 状态设置为 commit。

对于处于 prepare 阶段的 redo log,即可以提交事务,也可以回滚事务,这取决于是否能在 binlog 中查找到与 redo log 相同的 XID,如果有就提交事务,如果没有就回滚事务。这样就可以保证 redo log 和 binlog 这两份日志的一致性了。

主从复制是什么

分库分表了解吗

http://www.dtcms.com/a/449171.html

相关文章:

  • .NET周刊【9月第2期 2025-09-14】
  • 秦皇岛企业网站建设wordpress 悬浮音乐
  • 日语学习-日语知识点小记-进阶-JLPT-N1阶段应用练习(6):语法 +考え方19+2022年7月N1
  • 【Linux指南】gdb进阶技巧:断点高级玩法与变量跟踪实战
  • 跨平台游戏引擎 Axmol-2.9.0 发布
  • 金融 - neo4j、Graph Data Science 安装
  • c 可以做网站吗梧州seo排名
  • LuaC API知识点汇总
  • mysql学习--DCL
  • 开源 C++ QT QML 开发(七)自定义控件--仪表盘
  • 论坛开源网站源码网站建设实验总结报告
  • Ansible实战:VMware下K8s自动化部署指南
  • Ansible(三)—— 使用Ansible自动化部署LNMP环境实战指南
  • 【深度学习新浪潮】有没有可能设计出一种统一架构,可以同时处理图像理解的各种下游任务?
  • 介绍一下什么是RabbitMQ的发送者可靠性?
  • 网站后台管理页面模板北京企业建网站定制价格
  • AI编辑器(二) ---调用模型的fim功能
  • UniApp 自定义导航栏适配指南:微信小程序胶囊遮挡、H5 与 App 全端通用方案
  • 数据结构其一 线性表
  • 2025年--Lc164--H14.最长公共前缀(数组和字符串)--Java版
  • 网站html有了怎么建设网站钉钉小程序开发
  • Linux基本指令(2)
  • 从工具到中枢:2025 年 AI 重构实体经济的实践图景
  • 虚幻基础:攻击 与 受击 之间的联动
  • 如何在不降低画质的前提下缩小图片体积?附实操方案
  • 个人网站注册费用互联网广告价格
  • 【学习笔记02】C++面向对象编程核心技术详解
  • vite与ts的结合
  • arcgis如何将一部分shp地图截取下来并处理成networkx格式
  • .NET Aspire深度解析:重新定义云原生分布式应用开发的“秘密武器“