mysql-1-面试题基础

ACID 事务具有四个特征

事务就是一组原子性的操作,这些操作要么全部发生,要么全部不发生。事务把数据库从一种一致性状态转换成另一种一致性状态。

原子性

事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做

一致性

事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态
即使在执行第三、四条语句之间时系统崩潰,信用卡账户也不会损 失100块,
因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中,保证数据一致性。

隔离性

一个事务的执行不能其它事务干扰。
即一个事务内部的操作及使用的数据对其它并发事务是隔离的,
并发执行的各个事务之间不能互相干扰

持续性

指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。
接下来的其它操作或故障不应该对其执行结果有任何影响


Mysql的四种隔离级别以及带来的问题

Read Uncommitted(读未提交)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。
本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。
读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读已提交)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。
它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。
这种隔离级别 也支持所谓 的 不可重复读(Nonrepeatable Read),
因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重复读)

这是MySQL的默认事务隔离级别
它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。

Serializable(可串行化)

通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。
简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

拓展

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
脏读是因为其他事务的回滚

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,
对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
不可重复读是因为其他事务的提交

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,
但是系统管理员B就在这个时候插入了一条具体分数的记录,
当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
幻读是其他事务的插入或者删除,强调的是 行数 变化


MySQL支持哪些存储引擎?

MySQL支持多种存储引擎,比如:

InnoDB 支持事务,行级锁,以及外键,拥有高并发处理能力。但是在创建索引和加载数据时,比MyISAM慢。
MyISAM,不支持事务和行级锁。所以速度很快,性能优秀。可以对整张表加锁,支持并发插入,支持全文索引。
Memory,支持Hash索引,内存表,Memory引擎将数据存储在内存中,表结构不是存储在内存中的,查询时不需要执行磁盘I/O操作,所以要比MyISAM和InnoDB快很多倍,但是数据库断电或是重启后,表中的数据将会丢失,表结构不会丢失。
Archive等等
在大多数的情况下,直接选择使用InnoDB引擎都是最合适的,InnoDB也是MySQL的默认存储引擎。

MyISAM 和 InnoDB 的区别有哪些:

InnoDB支持事务,MyISAM不支持
InnoDB支持外键,而MyISAM不支持
InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高;MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针,主键索引和辅助索引是独立的。
Innodb不支持全文索引(FULLTEXT类型的全文索引),而MyISAM支持 全文索引,查询效率上MyISAM要高;
InnoDB不保存表的具体行数,MyISAM用一个变量保存了整个表的行数。
MyISAM采用表级锁(table-level locking);InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁。
表的具体行数,MyISAM保存有表的总行数;InnoDB则没有。
存储结构不一样,MyISAM在磁盘上存储成三个文件:.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。InnoDB所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空


聚簇索引

在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据
这就是非聚簇索引和聚簇索引.

在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引.
如果没有唯一键,则隐式的生成一个键来建立聚簇索引。

当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询.

那非聚簇索引一定会回表查询吗?

不一定,这涉及到查询语句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再进行回表查询。
比如:SELECT id FROM t_user WHERE id =1; 第一次查询已经拿到了id 就不用再回表查询了


MySQL中的varchar和char有什么区别.

char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容,该字段都占用10个字符
而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1最后一个字符存储使用了多长的空间.

char效率更快一点 char是固定长度的,而varchar需要增加一个长度标识,处理时需要多一次运算
在检索效率上来讲,char > varchar
因此在使用中,如果确定某个字段的值的长度,可以使用char,否则应该尽量使用varchar.
例如存储用户MD5加密后的密码,则应该使用char

超大分页怎么处理?

数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select ※ from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select ※ from table where id in (select id from table where age > 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快。


事务的实现原理

事务是基于重做日志文件(redo log)和回滚日志(undo log)实现的。

每提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库就可以通过重做日志来保证事务的原子性和持久性。
每当有修改事务时,还会产生undo log,如果需要回滚,则根据undo log 的反向语句进行逻辑操作,比如insert 一条记录就delete 一条记录。undo log 主要实现数据库的一致性

drop、delete与truncate的区别

drop直接删掉表有关的一切(数据/结构/约束…),不会记录日志,为DDL(Data Definition Language,数据库定义语言)操作。

truncate 删除表中所有数据(再插入时自增长id又从1开始),该操作也不会记录日志所以比较快,为DDL操作。只能删table。

DELETE语句执行删除的过程是每次从表中删除一行,需要记录日志,比较慢,可以加where 语句,为DML(Data Manipulation Language, 数据操纵语言)。

速度上drop > truncate > delete


哪些情况需要创建索引?

主键自动建立唯一索引
频繁作为查询条件的字段
查询中与其他表关联的字段,外键关系建立索引
单键/组合索引的选择问题,高并发下倾向创建组合索引
查询中排序的字段,排序字段通过索引访问大幅提高排序速度
查询中统计分组字段

哪些情况不要创建索引?

表记录太
经常增删改的表
数据重复且分布均匀的表字段,只应该为最经常查询和最经常排序的数据列建立索引
(如果某个数据类包含太多的重复数据,建立索引没有太大意义)
频繁更新的字段不适合创建索引(会加重IO负担)
where条件里用不到的字段不创建索引


百万级别或以上的数据如何删除

关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。

所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。

所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
然后删除其中无用数据(此过程需要不到两分钟)
删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。那更是坑了。


索引

MySQL官方对索引的定义为:
索引(Index)是帮助MySQL高效获取数据的数据结构。
我们可以简单理解为:快速查找排好序的一种数据结构。Mysql索引主要有两种结构:B+Tree索引和Hash索引。

索引一般分为:

普通索引:对关键字没有限制
唯一索引:要求记录提供的关键字不能重复
主键索引:要求关键字唯一且不为null
删除索引语法:

1
alter table 表名 drop KEY 索引名

binlog的类型

1. Statement模式:

在Statement模式下,MySQL将每个SQL语句作为一个事件记录到Binlog中。
具体来说,每个更新操作(如INSERT、UPDATE、DELETE等)都以SQL语句的形式被记录。
优势:
易读性高: Binlog中记录的是SQL语句,便于人类阅读和理解。
节省空间: 因为记录的是SQL语句,所以通常比其他模式占用更少的存储空间。
适用场景:
• 基于SQL语句的复制: 当使用基于SQL语句的复制技术,或者要求Binlog具有高可读性时,可以选择Statement模式。
注意事项:
• 可能引发非确定性问题: 由于某些SQL语句的执行结果可能会受到环境和状态的影响,因此在一些特定场景下可能会引发非确定性问题。

2. Row模式:

在Row模式下,MySQL将每个被修改的行的内容作为一个事件记录到Binlog中。不再记录SQL语句,而是记录数据行的变更情况。
优势:
• 更精确: 记录了实际被修改的行,不受SQL语句的语法或环境影响,更为精确。
• 避免非确定性问题: 由于记录了行的具体变更情况,避免了某些非确定性问题。
适用场景:
• 要求更高精度的数据复制: 当要求更高的数据复制精度,或者在一些需要避免非确定性问题的场景中,可以选择Row模式。
注意事项:
• 占用更多存储空间: 由于记录了每个被修改的行,所以通常比Statement模式占用更多的存储空间。

Mixed模式:

Mixed模式是Statement模式和Row模式的结合,MySQL会根据具体的SQL语句来选择使用Statement模式或Row模式。
大多数情况下,MySQL会选择Statement模式,但对于某些特殊的情况,会使用Row模式。
优势:
灵活性: 根据具体情况动态选择合适的模式,兼顾了Statement和Row模式的优势。
适用场景:
• 在大多数情况下使用Statement模式,但对于一些特殊情况使用Row模式: Mixed模式在大多数情况下保持了Statement模式的高效性,但在需要更高精度的情况下可以动态切换到Row模式。
注意事项:
• 可能引发非确定性问题: 在Statement模式下可能存在的非确定性问题,在Mixed模式下仍然可能存在。

选择合适的Binlog模式:

• 考虑复制技术和需求: 如果使用基于SQL语句的复制技术,Statement模式可能更合适。如果要求更高的数据精度,Row模式可能更适用。
• 考虑存储空间: 如果对存储空间比较敏感,可以选择Statement模式。如果数据精度是更为关键的因素,可以选择Row模式。
• 使用Mixed模式: 如果希望在大多数情况下保持高效性,但对于某些特殊情况需要更高精度,可以选择Mixed模式。

MySQL的binlog有有几种录入格式?分别有什么区别?

有三种格式,statement,row和mixed.

statement模式下,记录单元为语句.即每一个sql造成的影响会记录.由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制.

row级别下,记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大。

mixed. 一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row. 此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录