目录
MySQL表设计时间列用datetime还是timestamp?
Mysql索引有哪些缺点?以及具体有哪些索引类型?
第一、索引的优缺点
优点:1.合理的增加索引,可以提高数据查询的效率,减少查询时间。
2.有一些特殊的索引,可以保证数据的完整性。比如唯一索引。
缺点:1.对创建索引的表进行数据的增加、修改、删除时,会同步动态维护索引,这
部分会造成性能影响。
2.创建索引和维护索引需要消耗时间,并需要额外的占用物理空间
第二、索引的类型
1.主键索引:(数据列不允许重复,不允许为null,一个表只能有一个主键)
2.唯一索引:(数据列不允许重复,允许为null,一个表允许多个列创建索引)
3.普通索引:(基本的索引类型,没有唯一性的限制,允许为null值)
4.覆盖索引:查询列要被所建的索引覆盖,不必读取数据行
5.组合索引:多列值组成一个索引,用于组合搜索,效率大于索引合并
Mysql事务的实现原理?
(Mysql里面的事务满足ACID特性。原理就是InnoDB是如何保证ACID这样一个特性。)
首先,A表示Atomic原子性,需要保证多个DML操作的原子性【原子性:要么都成功,要么都失败】,
那么失败就意味着,对原本执行成功的数据要进行回滚。所以在InnoDB里面设计一个UNDO_LOG表。
在事务执行的过程中,把修改之前的数据快照保存到undo_log里面,一旦出现错误就直接从UNDO_LOG
里面读取数据,进行反向操作就可以了。
其次就是C,C表示一致性(数据的完整性约束没有被破坏),这个更多是依赖业务层面的一些保障。数据库
本身提供了像主键的唯一约束、字段长度和类型的一些保障等等。
接下来i,I表示事务的隔离性也就是说多个并行的事务对同一个数据进行操作的时候。如何去避免多个事务
的干扰到数据混乱的一个问题。而InnoDB里面实现了SQL92的一个标准,提供了四种隔离级别的一个实现。
1.RU(未提交读) 2.RC(已提交读) 3.RR(可重复读) 4.Serializable(串行化)
InnoDB默认采用的隔离级别是RR,然后使用了MVCC机制,去解决了脏读和不可重复读的一个问题。然后使用
了行锁/表锁的方式来解决了幻读的问题。
最后一个是D(持久性),也就是说只要事务提交成功那么对于这个数据的结果的影响一定是永久的。不能因为数
据库宕机或者其他原因导致数据变更失效。
理论上,事务提交之后,直接把数据放到磁盘中就0K了。但是随机磁盘IO效率确实很低,所以InooDB
里面设计了Buffer Pool缓存区进行优化,也就是说数据发生变更的时候,先更新内存缓冲区,然后
在合适的时间再持久化到磁盘里面。
那么在这个机制里面,有可能出现在持久化这样一个过程中数据库宕机就会导致数据丢失。(无法满足
持久化)。所以在InnoDB中引入了Redo_LOG这样一个文件。这个文件存储了数据库变更之后的一个值,
当我们通过事务进行数据更改的时候,除了修改内存缓存区的数据以外还会把本次修改的一个值追加到
Redo_LOG里面。当事务提交的时候,直接把Redo_LOG里面的日志刷新到磁盘里面进行持久化。一旦
数据库发生宕机,在mysql重启之后直接用Redo_LOG里面保存的重写日志读取出来以后再去执行一次。
从而去保证数据的持久性。
总的来看,事务的持久性原理核心本质原理就是如何去保证事务的ACID特性。而在UNDO_LOG里面用到了
MVCC、行锁、表锁、UNDO_LOG以及Redo_LOG等等这些机制去保证事务的ACID特性。
(设计思想:乐观锁、利用内存的缓冲区的方式来以空间换时间的思想去优化磁盘io的性能等等。
比如在分布式事务框架Seata的AT模式的数据回滚就借鉴了InnDB里面的UNDO_LOG的设计思想)
说一下行锁、临键锁、间隙锁的理解?
都是Mysql里面InnoDB引擎下去解决事务隔离性的一系列排他锁。
行锁:也称为记录锁,当我们针对组件或者唯一索引加锁的时候Mysql默认会对查询这行数据增加行锁,
避免其他事务对这一行数据进行修改。
(--其中id为主键索引 SELECT * FROM test WHERE id =1 FOR UPDATE;)
间隙锁:就是锁定一个索引区间。在普通索引或者唯一索引的列上,由于索引基于B+树的一个结构存储。
所以默认会存在一个索引的一个区间。就是某个事务对索引列加锁的时候,默认锁定对应索引的左右开区
间的一个范围。在基于索引类范围的查询中无论是否是唯一索引都会自动触发一个间隙锁。比如基于
between范围查找的过程中就会产生一个左右开区间的一个间隙锁。
(比如:--锁定:(5,7)select * from test where id between 5 and 7 fro update)
临键锁:它相当于行锁+间隙锁的一个组合,也就是说它的锁定范围既包含**索引记录**也包含了**索引
区间**,它会锁定一个左开右闭的一个数据范围。
-- 临键锁,锁定区间(10,11] select * from test where age=ll for update;
假设我们使用非唯一索引进行查询默认会加一个临键锁,锁定一个左开右闭区间一个范围。
所以总的来说行锁、临键锁和间隙锁它只是表示锁的数据的一个范围,终目的是为了解决幻读的这样一个问题。
而临键锁相当于行锁+间隙锁的一个组合。因此我们使用非唯一索引进行精准匹配的时候会默认加一个临建锁。
因为需要锁定匹配的一行记录还需要锁定这一行数据对应的左开右闭区间。因此在实际应用过程中尽可能
的就是使用**唯一索引**或者**主键索引**进行数据查询。避免大面积锁定造成性能的影响。
考核:关于事务隔离级别以及解决事务隔离级别一些底层实现
如何在保证数据安全性的情况下去平衡性能
行锁:

间隙锁:

临界锁:


Mysql中的数据预加载机制引发的思考?
问题解析:
Mysql在数据IO层面面临挑战,以及它的解决思路。Mysql数据存储到磁盘上,而读写磁盘的
速度相对内存来说是很慢的。所以为了优化磁盘IO性能,在Mysql中引入了一个缓冲池的概念。
(Buffer_pool机制)它会把一部分经常访问的数据缓存到内存里面,从而去提高数据的访问速度。
有了缓冲池以后当读取数据的时候,如果数据存在于Buffer Pool中。
客户端会直接读取Buffer Pool中的数据,否则再会去磁盘读取。
客户端修改数据的时候,首先也是修改Buffer Pool中数据所在的页,然后再把它的页设置为
脏页。最后由后台线程把脏页写入磁盘中。缓冲池的存在很大程度上减少了磁盘I/O带来的性能
开销。要操作的数据行所在的数据页如果存在缓存中的话,就不需要从磁盘中读取了。这样执行
以后就可以快速拿到结果。所以只要不存在或者减少磁盘I/O执行速度自然就会变快。
而预加载机制,就是更进一步减少磁盘IO的一个方式,InnoDB会把存储的数据划分为若干个页。以页
作为磁盘和内存交互的一个基本单位。一个页的默认大小是16kb,也就是一次读取会读取16kb的数据
缓存到Buffer Pool中。但是在程序中是有个叫空间局部性特征,也就是说当前读取磁盘上这一个数
据相邻的数据在未来很大概率也会被使用到。所以Mysql在加载数据页的时候会提前把它相邻的数据页
一并加载进来。目的就是为了减少磁盘IO,这就是所谓的预加载机制。在Mysql中提供了线性预读和随
机预读两种实现方式。
总的来说,基于空间局部原理实现预加载机制以及空间换时间思想下实现的Buffer Pool缓存池
的机制,都是在解决磁盘IO性能问题的设计方案。
Mysql中那些令人震撼架构设计思想
为了实现CRUD数据存储(索引、事务、存储)
问题分析:Mysql数据库的数据是存储在磁盘上的,当执行一条查询语句的时候,理论上Mysql需要
从磁盘上进行多次随机IO获取数据内容,进行返回。很明显由于磁盘IO性能相对比较低会导致一次查
询可能需要几十秒的响应,这显然不符合企业级应用的需求。因此Mysql为了解决这些性能问题做了几
方面的优化:
1.如图1引入了Buffer_pool缓冲池的设计,它是在内存中开辟了一块区域用来缓冲磁盘中的数
据;在Mysql启动的时候,InnoDB会为Buffer Pool申请一片连续的内存空间,然后按照默认的
16kb大小划分为一个一个的页(Buffer_pool中的页叫缓存页)。此时缓存页都是空闲的之后随着
程序的运行才会有磁盘上的数据页被缓存到Buffer_pool中。(这是一种典型的空间换时间的设计
思想:比如Mybits的多级缓存设计)
2.引入索引机制:依然是解决磁盘IO性能较慢的问题。具体来说,如果我们想查找指定的数据行
那么我们需要多次磁盘IO进行寻址。如果数据量很大的情况下IO次数会非常多,而且性能会比较
差。而通过索引的方式来组织数据存储,可以减少磁盘IO的次数。
3.引入查询优化器:使得用户提交了查询sql的执行计划,能够达到一个相对比较好的水平。
4.Mysql在数据持久化的时候,采用了追加的方式。记录到REDO_LOG的日志文件中,追加是采用
了一个磁盘顺序写。磁盘顺序写的性能是很高的,几乎和内存的随机读写的性能差不多。因此数据
写入磁盘的性能同样得到了很大的提升。
另外在解决事务并行冲突的场景中,引入了MVCC乐观锁的设计,降低了加锁带来的性能开销的影响。

MySQL表设计时间列用datetime还是timestamp?
问题解析:
MYSQL中时间列的选择问题涉及到许多方面的考虑,包括存储空间、时区支持、时间范围等等。
选择合适的时间类型不仅能够让你的数据库更加高效,还有助于避免一些常见的时间相关错误。
面试官提出这个问题的目的可能是了解你是否能够根据项目中的实际需求来做出合理的数据库
设计决策。
问题回答:
从三个方面来回答,
1.datetime和timestamp的区别,首先存入空间层面,timestamp占用四个字节,而
datetime占用八个字节。所以如果对存储空间有严格要求,Timestamp是一个更好的选择。
其次是时区支持timeStamp存储的是一个utc时间,会根据系统时序进行一个自动转化,
而datetime,不会做持续转化,存储的是字面值的时间。如果这业务程序需要在不同的时序
之间进行工作,那么timestamp可能是一个更合适的选择。接下来就是时间范围,datetime
的时间范围从1000年到9999年,timestamp它的时间范围是1970年到2038年。所以你需要
根据表述的时间范围来选择合适的类型。
2.选择上的建议。如果你需要存储的时间如果你需要存储的时间超出了datetime的范围,或者
你不想让时去影响存储时间时,可以使用datetime,如果你需要考虑到不同地区的时区问题,
或者希望节省存储空间,那么你可以使用datetime。
3 .在实际开发过程中呢,我们。需要注意几个方面,首先我们需要明确项目的需求和期望的行为,
不要盲目的选择。其次呢,在代码中统一时间处理方式,以避免失去转化的问题。
总的来说,datetime和他们有各自的信用场景和优点。理解他们的特点和区别,能够帮助我们做
出更好的选择。
PostgreSQL数据库对于MySQL之间的一些对比
问题解析:
开发中,数据存储和管理是一个非常重要的环节。 Mysql和PostgreSQL都是目前广受欢迎
的开源关系性数据库,他们在许多方面有相似的特点,比如说都是一些ACID事务,都有稳定
的性能和高可用性。然而,在一些细节和特性上,它没有存在一些差异。一些差异可能会影响
到我们根据特定项目的需求去选择合适数据库。而在选择数据库的时候,我们必须要权衡选择
因素,比如说性能、可靠性、特性支持等等。所以,面试官提出的问题,一方面他希望了解你
对两种共同数据库系统的理解程度,是否清楚他们的特性和适用场景,另外一方面,他也可能
希望看到你对技术具有深度思考的能力,也就是如果根据项目需求去做技术决策。而不是盲目
的跟随某种技术。下面我们看一下这个问题的回答。
问题回答:
首先我认为Mysql和PostgreSQL都是非常优秀的数据库系统,我会根据具体的项目需求来选
择使用哪一个,下面我就针对这两种数据库区别进行一个简单说明。第一,特性层面,PDCQ提
供了一些高级特性,比如物化视图、 公共表表达式和窗口函数等等,而MYCQ在一些web开发中
表现更加优秀,第二个性,总体来说啊,MYCQ的性能更加突出,特别是在读密集型的场景中。
而PGCQ在处理复杂查询和写密集操作时更有优势。第三一致性和数据完整性。BDCQ更严格遵循
SQL标准,提供了全面的ACID支持,而MYCQ呢,虽然也支持ACID,但它的支持程度会受到所使
用存储引擎的影响。第四,扩展性。PostgreSQL就是多种制定扩展,比如说自定义数据类型、
操作符等等,而MYSQL呢,则是在分区等方面表现更好。
对于PDCQ和MYCQ的选择,有几个方面的考虑因素:
第一,从应用范围来说,PDCQ更适合具有频繁写入操作和复杂查询的企业级应用程序。但是如
果想要创建用户较少的内部用户程序,或者创建具有更多读取次数和较少数据更新的信息存储引
擎,那么就可以使用MYSQL,从学习的难易程度来说,MYSQL更适合重学者。他的学习曲线更短
,从头开始构建新的数据库项目所需要的时间更少。PostgreSQL需要复杂的基础设置和问题排
查经验。第三和性能方面来说,如果应用程序需要频繁更新数据。
PostgreSQL是更好的选择。但是如果需要频繁的读取数据,就首选MYSQL。在数据写入层面,
MYSQL是用解锁来实现真正的并发性,而PostgreSQL呢,内置多版本并发控制支持,没有读写
锁定,如果要进行频繁并发的写入操作,PostgreSQL数据库的表现会更加优异。在数据库读取
层面。PostgreSQL会创建一个新的系统进程,为每个连接到数据库的用户分配大量内存,而
Mysql是为多个用户创建一个单一进程,因此对于主要向用户读取和显示数据的应用程序,
Mysql数据库要比PostgreSQL要更好一点。
请说一下MySQL索引失效场景?

MySql是我们提高查询效率的重要工具,MySQL中采用了b+树作为索引结构,来减少
磁盘IO次数。
1.查询语句设计不合理
2.对MySQL的理不够深入
有可能会失效
这时候查询语句就会变成一个全表扫描,这对于大数据量的数据库来说是非常低效的。了解
这些索引的失效场景。能够
更好地利用索引
提高SQL查询的效率
考查:是否对MySQL有深入的了解
是否正确地使用索引
问题回答:
在Mysql中索引失效的场景有以下几种:
1. 在 WHERE子句中使用一些逻辑操作符;比如NOT IN,≠会导致MySQL无法进行索引
查找;
2.对索引字段进行计算或函数操作; 比如做一个YEAR()函数操作ySQL无法使用索引;
3.使用LIKE操作符进行模糊查询时,通配符前面那么就会导致索引失效。因为MySQ
无法去确定查找的起始点;
4.如果Mysql估计全表扫描比索引速度更快,它会选择全表扫描;比如数据量小或者大
部分行都满足WHERE子句的时候;
5.在复合索引中,如果没有按照索引的最左前缀的顺序来查,也可能会导致索引失效;
避免这些常见索引失效的场景,能够帮助
1.更好地利用索引;
2.提高SQL查询的效率;
强化版:


MySQL自增ID用完后会怎么样?
问题解析:
一个表的主键ID基本上都是采用数据库AUTO_INCREMENT来实现,对于一个int类型
的无符号自增ID。最大能够存储的数据量是20多个亿(2147483647),当达到最大值的时候
ID就不会自增,最后就会出现组件冲突问题,导致数据无法插入。
实际上一个表不太可能会存储几十亿的数据,因为这么大数据要实现数据的查找和插入
的性能是非常低的。考查:1. 对数据库设计和管理的理解;2,对数据库性能优化的思考;
3.对于错误处理和故障恢复相关的理解;
问题回答:
MySQL自增ID用完以后,后续插入数据的时候,ID不会再递增,从而就会导致出现主键
冲突,使得数据无法正常保存(注意:这个问题一般不会出现); 因为即便是int类型的主
键,也能存储20多个亿的数据量;假设真的存在这样一个问题,有几个解决思路:
1. 可以在设计前期就考虑到这个点,把id的数据长度设置更大,比如bigint;
2. 不使用自增id,而是采用业务主键,这样后期做分表的时候更加方便;
3. 假设已经存在这样的瓶颈了可以考虑把数据迁移到一个新的表或新的数据库中,然后
重置自增ID的范围;但是这个过程需要谨慎处理,从而确保数据一致性和业务逻辑的正确
性;
什么是最左匹配原则?
问题解析:
最左匹配原则通常指的是索引的匹配方式:
当查询语句中有多个条件,并且这些条件可以使用索引进行匹配时,数据库系统会使用最
左匹配原则来选择最适合的索引进行查询。
举个例子:比如有这样的联合索引(column1,column2),如果查询语言的条件是这样的
形式:条件 column1=1 AND column2=2;但是in和=这两个操作符允许乱序匹配;
再比如:(a,b,c) select * from t where c=1 and a=1 and b=1,那么
我们可以通过这一个SQL语句是可以实现最左匹配;因为MySQL中有一个优化器,它会对
这个SQL语句进行分析和优化,最终能够去匹配对应索引形式,也就是最终会优化成这样
一个结构;select * from t where a=1 and b=1 and c=1
MySQL update 是行锁还是表锁?
Mysql中为什么要引入锁?
在多个事务并行对同一个数据进行修改的时候,会产生事务的竞争会造成脏读、幻读、不可重复读
等问题。所以Mysql为了避免这类问题的出现,引入了事务的隔离级别。其实本质上来说,最终解决
的方式无非就是LBCC和MVCC两种,而锁的解决事务竞争问题的底层实现方式。通常来说加锁会影响
性能,所以一般情况下会考虑到性能和安全的平衡。 而Mysql根据不同的作用范围提供了不同锁的
实现方式。
而这个问题考查对于锁范围的理解。
问题回答:
Mysql的Update操作既可以是行锁也可以是表锁。具体使用哪种方式类型的锁取决于update
语句的条件,事务隔离级别等因素。
如果update语句中的where条件包含了索引列,并且只更新一条数据行。那这时候就会加行锁;
如果where条件中不包含索引列,这个时候会加表锁。
另外根据查询范围不同,Mysql也会选择不同粒度的锁来避免幻读的问题。比如针对主键索引的
for update操作。 select * from t where id = 10 for update
Mysql会增加一个Next-Key Lock 来锁定id=10索引所在的区间。
select * from t where BETWEEN 1 AND 100 for update
而针对索引区间的查询或者修改,Mysql自动对索引加间隙锁来解决幻读问题。
Mysql数据库CPU飙升要怎么处理?
第一步、排查问题
1.我们可以使用top命令,找到CPU占过高的进程是否是mysqld。
2.如果是的话,可以在mysql中通过show processlist去查询当前的会话情况。确定是否有消耗
资源的SQL正在运行。
3.找到消耗过高的SQL,通过执行计划进行具体的分析,然后针对性的优化。
第二步、处理方式
如果确定是SQL问题,可以通过SQL优化手段进行调整。调整完之后可以重新执行SQL来分析,确认是
否达到优化的目的。
第三步、其他情况
如果不是SQL的问题导致的,那么我们需要分析CPU飙高的时间段。Mysql的整个并发连接数量,如果
有大量的请求连接进来。那我们就需要分析这个时间业务的情况,再做出相应的调整。
最后,如果是Mysql本身的参数不是最佳的状态,那我们可以对Mysql服务节点的配置进行调整。比如
缓存大小、线程池大小等等。
总结一下,处理Mysql数据库CPU飙升的问题,需要综合考虑多个方面。包括查询优化、索引优化、
Mysql配置优化、硬件升级、负载均衡等等。
Mysql索引有哪些缺点以及具体有哪些索引类型?
第一、 索引的优缺点
优点:1.合理的增加索引,可以提高数据查询的效率,减少查询的时间;
2.有一些特殊的索引,可以保证数据的完整性;比如唯一索引
缺点:1.创建索引和维护索引需要消耗时间;
2.索引需要额外占用物理空间;
3.对创建索引的表进行数据增加、修改、删除时,会同步动态维护
索引,这部分会造成性能的影响。
索引是一种能够帮助Mysql高效去磁盘去检索数据结构,在Mysql中的InnoDB引擎里面
采用的是B+树的结构来实现索引和数据的存储。
优点:
1. 通过B+树的结构来存储数据,可以大大减少数据检索的磁盘IO次数,从而提升数据查
询的性能;
2. B+树索引在进行范围查找的时候,只需要找到起始节点,然后基于叶子节点的链表结
构往下读取即可查找效率较高;
3. 通过唯一索引约束,可以保证数据表中每一行数据的唯一性;
缺点:
1. 数据的增加、修改、删除,需要涉及到索引的维护,当数据量较大的情况下,索引的
维护会带来较大的性能开销;
2. 一个表中允许存在一个聚簇索引和多个非聚簇索引,但是索引不能创建太多,否则造
成的索引维护成本过高;
3. 创建索引的时候,需要考虑到索引字段值的分散性,如果字段的重复数据过多,创建
索引反而会带来性能降低;
第二、索引的类型
1、主键索引:
数据列不允许重复,不允许为NULL,一个表只能有一个主键;
2、唯一索引:
数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引;
3、普通索引:
基本的索引类型,没有唯一性的限制,允许为NULL值;
4、全文索引:
是目前搜索引擎使用的一种关键技术,对文本的内容进行分词、搜索;
5、覆盖索引:
查询列要被所建的索引覆盖,不必读取数据行;
6、组合索引:
多列值组成一个索引,用于组合搜索,效率大于索引合并;
Mysql的 binlog有几种格式?
有三种:
statement
row
mixed
statement:是记录的是SQL的原文,它的好处是不需要记录每一行的变化,减少了blog的日志量、
节约了IO、从而提升了性能。由于SQL的执行是有上下文的,因此在要保存相关的一些信息。同时
还有一些使用了函数之内的语句是无法被记录复制的。
row:它不会记录SQL的上下文信息,仅仅是保留哪一条记录被修改。记录单位为每一行的改动,基本
上 可以全部记下来。但是由于很多操作会导致大量行的改动,因此这种模式下上下文保存信息会比较
多,日志量会比较大。
mixed:它是一种折中的方案。普通操作使用statement记录,当无法使用statement记录的时候。
会使用row.
怎么解决Mysql主从集群同步延迟问题?
主从复制的工作原理:
1. 主库更新事件,比如说update、insert、delete被写到binlog;
2. 从库发起连接,连接到主库;
3. 此时主库创建一个binlog dump thread把binlog的内容发送到从库;
4. 从库启动后创建一个IO线程,读取主库传过来的binlog内容并写入到relay log;
5. 从库还会创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos
位置开始执行读取到的更新事件,将更新内容写入到从库里面;
主从数据同步涉及到网络数据传输,由于网络通信的延迟,以及从库数据处理的效率问题。
就会导致主从数据同步延迟的一个情况,一般可以通过几种方式来解决:
1.设计一主多从的方式来分担从库的压力,减少主从同步延迟的一个问题;
2.如果对数据一次要求较高,那么在从库存在延迟的情况下,可以强制走主库查询数据;
3.可以在从库上执行show slave status命令,获取seconds_behind_master
字段的延迟时间,然后sleep阻塞等待固定时间后再次查询;
4.可以通过并行复制解决从库复制延迟的问题;
实际上主从复制的场景,无法避免同步延迟这样一个情况;如果一定要用强一致方案那
就应该考虑到其他能够实现实时数据一致性的一个技术方案;

Mysql中的RR隔离级别,到底有没有解决幻读问题?
会出现幻读的问题,所谓幻读表在同一个事务中的两次相同条件的查询,得到的数据条数不一样。
那么在RR的隔离级别下具体什么情况会出现幻读。 如图情况:在事务1里面通过update语句
触发了当前读的情况下就会导致在该事务中的前后两次查询数据行数不一致,从而出现幻读现象。
导致幻读的根本原因是:
update操作会触发当前读操作,绕过了快照读;从而导致MVCC机制在当前的场景下失效,
最终读取到了事务2中。已经提交的数据为了避免在涉及的开发中遇到这一类的问题,我们可以
通过for update的语句去加锁。

Mysql是如何解决幻读问题的?
Mysql里面有四种事务隔离级别,这四种隔离级别代表当前存在多个事务。 并发冲突的时候
可能会出现脏读、不可重复读、幻读的问题。其中InnoDB里面RR隔离级别解决了幻读问题。
那什么是幻读?幻读是指同一个事务里面前后两次查询相同的范围的是时候得到数据条数不一样。
那在InnoDB里面如何解决这样的一个问题?
引入了间隙锁和临建锁的机制去解决幻读的问题。
假设现在存在这样一个B+树一个索引结构,这个结果里面有四个索引元素。分别是1、4、7和10。
当我们通过主键索引查询一条记录,并且对这条通过for update加锁的时候会产生一个记录也
就是行锁,会锁定id=1的这个索引。被锁定的记录在索引释放之前其他事务是无法对这个记录做
任何操作。前面有说过幻读的定义,幻读是指同一个事务中前后两次查询相同范围的时候
也就是InnoDB引擎要解决幻读的问题必须要保证一个点就是如果一个事务通过这样一个语句:
select * from t where id >=4 and id < 7 for update
进行锁定的时候另外一个事务在执行这样一条insert语句:
Insert inot t (id,name) values(5,'itcast');
需要被阻塞,直到前面获得锁的事务释放。所以在InnoDB中设计了一种间隙锁主要功能:锁定一段
范围内的索引记录。当对查询id>4 and id<7加锁的时候会针对于B+树种(4,7)这个开区间的范围
索引加间隙锁。意味着这个情况下其他事务对这个区间数据进行插入、更新、删除的时候都会被锁住。
但是还有另外一种情况,比如像这样一个查询语句:
select * from t where id > 4 for update;
是针对于id>4的这个条件加锁,那么它需要锁定多个索引区间,所以在这种情况下InnoDB引入了一个
next-key Lock的机制。next-key Lock相当于间隙锁和记录锁的集合,记录锁锁定存在的记录行,
间隙锁锁住的是记录行之间的间隙。而临键锁锁住的是两者之和,注意每个数据行上的非唯一索引列都
会存在一把临键锁。当某个事务持有该数据行的临键锁的时候会锁住一个左开右闭区间的数据。因此当
通过id>4这样一个范围查询加锁的时候,会加一个next-key Lock锁定的区间范围是这样的。
间隙锁和临键锁的区别在于加锁的范围,间隙锁只锁定两个索引之间的引用间隙。而临键锁会锁定多个
索引区间,它包含了记录锁和间隙锁。当我们使用的范围查询不仅仅命中了record记录,还包含了GAP
间隙,在这种情况下,我们使用的就是临键锁,它是Mysql里面默认的行锁算法。虽然InnoDB通过间
隙锁的方式解决了幻读的问题,但是加锁之后。一定会影响到并发性能,所以针对性能要求比较高的
业务场景,我们可以把隔离级别设置成RC,这个级别中呢,不存在间隙锁。









为什么Mysql要用B+树来实现呢,而不是B树?
首先,常规的数据库存储引擎一般都是采用B树或者B+树来实现,因为B树是一种多路平衡树,
用这种存储结构来存储大量数据的时候,它的整个数的高度相比二叉树来说会矮很多,而对
于数据库来说,所有的数据必然都是存在磁盘上,而磁盘IO的效率实际上是比较低的,特别
是在随机磁盘IO的情况下,效率更低。所以树的高度能够决定磁盘IO的次数,磁盘IO次数
越小,那么对于性能的提升就越大,这也是为什么采用B树作为所以存储结构的原因,但是
在MYSQL的InnoDB存储引擎里面呢,它用到了一种增强的B树结构,也就是B+树来作为索引
和数据的存储结构相比于B树结构来说,B+树做了几个方面的优化。
1.B+树的所有数据都存储在叶子节点,非叶子节点只存储索引。
2.叶子节点的数据使用双向列表的方式进行关联
使用B+树来实现索引的原因呢?我认为有几个方面,第一个,B加速的非叶子节点不存储
数据,所以每一层能够存储的索引数量会增加,意味着B加速在层高相同的情况下,存储的
数据量要比低树更多,使得磁盘的IO次数更少。第二个在MYSQL里面,范围查询是一个比
较常用的操作,而B加速的所有存储在叶子结构中使用的双向列表的方式来关联,所以在查
询的时候只需要查询两个节点进行遍历就行。而B数呢,需要获取所有节点,所以B加数在
范围查询上的效率更高,第三个在数据的解锁方面,由于所有的数据都存入了叶子节点,
所以B加数的IO次数会更加稳定,第四个因为叶子节点啊。存储所有数据,所以B加速的全
局扫描能力要更强,因为它只需要扫描叶子节点,但是B树需要遍历整棵树。另外,基于
B+树这样一个结构,如果采用自增的整型数据作为主键,才能更好的避免数据增加的时
候带来的叶子节点分裂导致大量运算的问题。
总的来说啊,我认为技术方案的选型更多的是去解决当前场景下的特定问题,并不
一定是说B加速就是最好的选择,就像Mongodb里面采用B树的结构,本上来说其实是
关系型数据库和非关系数据库的差异。





Mysql的性能调优方法
Mysql性能调优方法可以从四个方面来做:
第一、表结构和索引;
第二、SQL语句优化;
第三、Mysql参数优化;
第四、硬件及系统配置;
1.表结构和索引的优化:比如分库分表、读写分离。为字段选择合适的数据类型;
适当的反范式设计,为查询操作创建必要的索引等等;
2.SQL语句优化: 通过慢查询分析需要优化的SQL,利用explain或者profile
这些工具去分析SQL的执行计划;避免使用SELECT *的查询,尽可能使用索引扫
描等等;
3.Mysql参数调优:主要设置Buffer_pool的大小,官方建议占总内存的50%-
70%左右,设置刷盘策略平衡好数据安全性和性能的关系;
4.硬件及系统配置:CPU的核心数磁盘的读写性能、网卡、内存的大小等等;


数据量达到多少的时候要开始分库分表


Mysql中MyISAM和InnoDB引擎有什么区别?




问题回答:
MyISAM和InnoDB的区别有四个:
1.数据存储的方式不同:MyISAM里面的数据和索引时分开存储的;而InnoDB是把索引和数据存储
在同一个文件里面;
2.对于事务的支持不同:MyISAM不支持事务;而InnoDB支持ACID特性的一个事务处理。
3.对于锁的支持不同:MyISAM只支持表锁;而InnoDB可以根据不同的情况去支持行锁 、表锁、间
隙锁、临键锁;
4.MyISAM不支持外键;InnoDB支持外键;因此基于这些特性我们可以在实际应用中可以根据不同的
场景去选择合适的存储引擎。比如说如果需要去支持事务,那就必须要去选择InnoDB。如果大部分表
操作是查询可以选择MyISAM;
Mysql如何解决幻读问题?
问题解析:
数据库的事务隔离级别,不同的隔离级别对数据的安全性的影响是不同的。幻读、脏读和不可
重复读这样的问题。幻读就是一个事务前后两次读取到数据条数不一致。如图,在第一个事务
里面执行衣蛾范围查询,这时候满足条件的查询数据只有一条数据。接着第二个事务里面插入
一条数据并且提交了,然后再第一个事务里面再次执行查询的时候发现有两条数据满足条件,
有两条数据满足条件。在RR的事务隔离级别里面引入了MVCC和LBCC这两种方式去解决幻读问
题。MVCC类似于一种乐观锁的一个设计,简单来说就是针对每个事务生成一个事务版本然后
针对这个版本去顶一个访问规则。
第一个、一个事务只能看到第一次查询之前已经提交的事务以及当前事务的修改;
第二个、一个事务不能看到当前事务第一次查询之后创建的事务,以及未提交的事务修改;
但是如果在一个事务里面存在当前读的情况下MVCC还是会存在幻读的问题,因为当前读不是读
的快照而是直接读的内存,所以这样情况可以使用LBCC。也就是基于锁的机制来解决(行锁、
表锁和间隙锁等等)。
问题回答:
在RR也就是可重复读的一个事务隔离级别InnoDB采用了MVCC的机制来解决幻读的问题(MVCC
就是一种乐观锁的一个机制)。它是通过对于不同事务,生成不同的快照版本,然后通过UNDO
的版本链来进行管理,并且在MVCC里面它规定了高版本能够看到低版的一个数据变更。低版本
看不到高版本一个数据变更,从而去实现了不同事务之间的一个数据隔离,解决了幻读的问题。
但是如果在事务里面存在当前读情况那么它直接读取内存里面的数据(跳过了快照读),所以还
是会出现幻读的问题。我认为可以通过两种范式来解决:
1. 尽量去避免当前读的情况;
2. 是可以引入LBCC的方式;

Mysql 事务的实现原理
Mysql 里面的事务,满足 ACID 特性,所以在我看来,Mysql 的事务实现原理,就是 InnoDB 是如何
保证 ACID 特性的。
首先,A 表示 Atomic 原子性,也就是需要保证多个 DML 操作是原子的,要么都成功,要么都失败。
那么,失败就意味着要对原本执行成功的数据进行回滚,所以 InnoDB 设计了一个 UNDO_LOG 表,
在事务执行的过程中,
把修改之前的数据快照保存到 UNDO_LOG 里面,一旦出现错误,就直接从 UNDO_LOG 里面读取数
据执行反向操作就行了。
其次,C 表示一致性,表示数据的完整性约束没有被破坏,这个更多是依赖于业务层面的保证,数据库
本身也提供了一些,比如主键的唯一余数,字段长度和类型的保证等等。
接着,I 表示事务的隔离性,也就是多个并行事务对同一个数据进行操作的时候,如何避免多个事务的
干扰导致数据混乱的问题。
而 InnoDB 实现了 SQL92 的标准,提供了四种隔离级别的实现。分别是:
RU(未提交读)
RC(已提交读)
RR(可重复读)
Serializable(串行化)
InnoDB 默认的隔离级别是 RR(可重复读),然后使用了 MVCC 机制解决了脏读和不可重复读的问题,
然后使用了行锁/表锁的方式解决了幻读的问题。
最后一个是 D,表示持久性,也就是只要事务提交成功,那对于这个数据的结果的影响一定是永久性的。
不能因为宕机或者其他原因导致数据变更失效。
理论上来说,事务提交之后直接把数据持久化到磁盘就行了,但是因为随机磁盘 IO 的效率确实很低,
所以 InnoDB 设计了
Buffer Pool 缓冲区来优化,也就是数据发生变更的时候先更新内存缓冲区,然后在合适的时机再持久
化到磁盘。
那在持久化这个过程中,如果数据库宕机,就会导致数据丢失,也就无法满足持久性了。
所以 InnoDB 引入了 Redo_LOG 文件,这个文件存储了数据被修改之后的值,当我们通过事务对数据
进行变更操作的时候,除了修改内存缓冲区里面的数据以外,还会把本次修改的值追加到 REDO_LOG
里面。
当提交事务的时候,直接把 REDO_LOG 日志刷到磁盘上持久化,一旦数据库出现宕机,
在 Mysql 重启以后可以直接用 REDO_LOG 里面保存的重写日志读取出来,再执行一遍从而保证持久
性。
因此,在我看来,事务的实现原理的核心本质就是如何满足 ACID 的,在 InnDB 里面用到了 MVCC、
行锁表锁、UNDO_LOG、REDO_LOG 等机制来保证。
以上就是我对这个问题的理解!
面试点评
InnDB 的事务实现原理,有很多可以借鉴的设计思想,
比如乐观锁、利用内存缓冲区的方式,以空间换时间的思想优化磁盘 IO 的性能等等
这些思想还挺重要的,比如在分布式事务框架 Seata 的 AT 模式的数据回滚,就借鉴了
InnDB 里面 UNDO_LOG 的设计思想。
Mysql 索引的优点和缺点?

(图片)索引,是一种能够帮助 Mysql 高效从磁盘上检索数据的一种数据结构。
在 Mysql 中的 InnoDB 引擎中,采用了 B+树的结构来实现索引和数据的存储
在我看来,Mysql 里面的索引的优点有很多
1. 通过 B+树的结构来存储数据,可以大大减少数据检索时的磁盘 IO 次数,从而提升数据查询的性
能
2. B+树索引在进行范围查找的时候,只需要找到起始节点,然后基于叶子节点的链表结构往下读取
即可,查询效率较高。
3. 通过唯一索引约束,可以保证数据表中每一行数据的唯一性
当然,索引的不合理使用,也会带来很多的缺点。
4. 数据的增加、修改、删除,需要涉及索引的维护,当数据量较大的情况下,索引的维护会带来较大
的性能开销。
5. 一个表中允许存在一个聚簇索引和多个非聚簇索引,但是索引数不能创建太多,否则造成的索引维
护成本过高。
6. 创建索引的时候,需要考虑到索引字段值的分散性,如果字段的重复数据过多,创建索引反而会带
来性能降低。
咕泡科技出品,严禁商用
在我看来,任何技术方案都会有两面性,大部分情况下,技术方案的选择更多的是看中它的优势 和当
前问题的匹配度。
以上就是我对这个问题的理解
Mysql为什么使用B+ Tree作为索引结构
首先常规的数据库存储引擎,一般都是采用B树或者B+树来实现索引的存储;因为B树是一种
多路平衡树。用这种存储机构来存储大量数据的情况下,它的整体高度相比二叉树来说会矮
很多。而对于数据库来说,所有的数据必然是存储在磁盘上而磁盘IO的效率实际上是最低的,
特别是在随机磁盘IO的一个情况下效率更低,所以树的高度就能决定磁盘IO的一个次数,磁
盘IO次数越少。那么对性能的提升就会越大,这也是为什么采用B树作为索引存储结构的原因。
但是,在Mysql的InnoDB存储引擎里面它采用的是一种增强的B树结构,也就是B+树来作为索
引和数据的一个存储结构。相比较于B树的结构,B+树做了几个方面的一个优化:
1.B+树所有数据存储在叶子节点,非叶子节点只存储索引;
2.叶子节点中数据使用双向链表的方式进行关联;
所以使用B+树来实现索引的一个存储结构的几个原因:
1.B+树非叶子节点不存储数据,所以每一层能够存储的索引数据会增加,意味着B+树的在
高层相同的情况下存储的数据量比B树要多,使得磁盘IO次数更少;
2.在Mysql中,范围查询是一个比较常用的操作,而B+树的所有存储在叶子节点的数据使
用了双向链表来关联,所以在查询的时候只需查两个节点进行遍历就行,而B树需要获取所
有节点,所以B+树在范围查询上效率更高;
3.在数据检索方面,由于所有的数据都存储在叶子节点,所以B+树的IO次数更加稳定一些;
4.因为叶子节点存储所有数据,所以B+树的全局扫描能力更强一些,因为它只需要扫描叶子
节点,因为B树需要遍历整个树;
另外基于B+树这一个结构,如果采用自增的整型数据作为主键,还能够更好的去避免增加数据的
时候,带来的叶子节点的分裂,导致了大量运算的一个问题。
总的来说,技术方案的选择更多是当前场景下的一些特定问题,并不一定说B+就是最好的选择就
像MongoDB里面采用B树结构,其实是关系性数据库和非关系数据库的差异。


Mysql的事务隔离级别
从几个方面回答:
1.事务的隔离级别是为了解决多个并行事务竞争导致数据安全的一种规范,具体来说
多个事务竞争可能会产生三种不同的一个现象。如图1假设有两个事务T1/T2同时在执行,
那么T1事务有可能会读取到T2事务未提交的数据。但是未提交的事务T2有可能会出现回滚,
也就导致T1事务读取到一个最终不一定存在的数据,从而产生一个脏读的一个现象。
2.假设两个事务T1/T2同时在执行,那么事务T1在不同的时刻,读取的同一行数据的
时候,有可能结果不一样。从而导致一个不可重复读的一个问题。
3.假设有两个事务T1/T2同时在执行,那么事务T1执行范围查询或者范围修改的一个
时候。事务T2插入一条属于事务T1范围内的数据,并且提交了。那么这个时候事务T1查询
时候发现多出了一条数据。或者说T1事务发现这条数据并没有被修改(这种现象称为幻读)。
而这三种现象在实际应用中里面可能有些场景不能接受某些现象存在,所以在SQL标准里面
定义了四种隔离级别:
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
(脏读、不可重复读、幻读)
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓 的 不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的 commit,所以同一 select 可能返回不同结果。
(不可重复读、幻读)
Repeatable Read(可重读)
这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。
(幻读)
Serializable(可串行化)
通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
(多个并行事务串行化执行,不会产生安全性问题,只有串行化解决了全部的问题)
但是这种隔离级别的性能是最低的,在Mysql里面InnoDB引擎默认的隔离级别是RR也就是可重复读,需要保证
事务ACID特性中的隔离性。




Redis 和 Mysql 如何保证数据一致性
一般情况下,Redis 用来实现应用和数据库之间读操作的缓存层,主要目的是减少数据库 IO,还可以
提升数据的 IO 性能。
这是它的整体架构。
当应用程序需要去读取某个数据的时候,首先会先尝试去 Redis 里面加载,如果命中就直接返回。如
果没有命中,就从数据库查询,查询到数据后再把这个数据缓存到 Redis 里面

(如图)在这样一个架构中,会出现一个问题,就是一份数据,同时保存在数据库和 Redis 里面,当
数据发生变化的时候,需要同时更新 Redis 和 Mysql,由于更新是有先后顺序的,并且它不像 Mysql
中的多表事务操作,可以满足 ACID 特性。所以就会出现数据一致性问题。
在这种情况下,能够选择的方法只有几种。
1. 先更新数据库,再更新缓存
2. 先删除缓存,再更新数据库
如果先更新数据库,再更新缓存,如果缓存更新失败,就会导致数据库和 Redis 中的数据不一致。
如果是先删除缓存,再更新数据库,理想情况是应用下次访问 Redis 的时候,发现 Redis 里面的数据
是空的,就从数据库加载保存到 Redis 里面,那么数据是一致的。但是在极端情况下,由于删除 Redis
和更新数据库这两个操作并不是原子的,所以这个过程如果有其他线程来访问,还是会存在数据不一致
问题。

如果是先删除缓存,再更新数据库,理想情况是应用下次访问 Redis 的时候,发现 Redis 里面的数据
是空的,就从数据库加载保存到 Redis 里面,那么数据是一致的。但是在极端情况下,由于删除 Redis
和更新数据库这两个操作并不是原子的,所以这个过程如果有其他线程来访问,还是会存在数据不一致
问题。

所以,如果需要在极端情况下仍然保证 Redis 和 Mysql 的数据一致性,就只能采用最终一致性方案。
(如图)比如基于 RocketMQ 的可靠性消息通信,来实现最终一致性。

(如图)还可以直接通过 Canal 组件,监控 Mysql 中 binlog 的日志,把更新后的数据同步到 Redis
里面。

因为这里是基于最终一致性来实现的,如果业务场景不能接受数据的短期不一致性,那就不能使用这个
方案来做。
以上就是我对这个问题的理解。
结尾
在面试的时候,面试官喜欢问各种没有场景化的纯粹的技术问题,比如说:“你这个最终一致性方案”
还是会存在数据不一致的问题啊?那怎么解决?
先不用慌,技术是为业务服务的,所以不同的业务场景,对于技术的选择和方案的设计都是不同的,所
以这个时候,可以反问面试官,具体的业务场景是什么?
一定要知道的是,一个技术方案不可能 cover 住所有的场景,明白了吗?
好的,好的,本期的普通人 VS 高手面试系列的视频就到这里结束了,喜欢的朋友记得点赞收藏。
另外,最近从评论区收到的面试问题,都有点太泛了,比如:说一下 mongoDB 啊,说一下 kafka 啊、
说一下并发啊,这些问题都是要几个小时才能彻底说清楚,建议大家提具体一点的问题。
我是 Mic,一个工作了 14 年的 Java 程序员,咱们下期再见。




1万+

被折叠的 条评论
为什么被折叠?



