Skip to content

MySQL、索引与 SQL ​

返回完整题目索引

来源:用户提供的《golang 云原生面试题》PDF。下列为原文完整导入,按主题重排;页码为 PDF 物理页码。技术观点与示例保留原件语境,勘误请结合 校正说明 阅读。

据库三大范式是什么 ​

PDF 出处:第 73–73 页 · 原卷分组:mysql · 源标题 p073-h03。

  1. 第一范式:每个列都不可以再拆分。

  2. 第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。

  3. 第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。

MySQL 有关权限的表都有哪几个? ​

PDF 出处:第 73–73 页 · 原卷分组:mysql · 源标题 p073-h04。

MySQL 服务器通过权限表来控制用户对数据库的访问,权限表存放在 MySQL 数据库里,由mysql_install_db 脚本初始化。这些权限表分别 user,db, table_priv,columns_priv 和 host。下面分别介绍一下这些表的结构和内容:

  1. user 权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。

  2. db 权限表:记录各个帐号在各个数据库上的操作权限。

  3. table_priv 权限表:记录数据表级的操作权限。

  4. columns_priv 权限表:记录数据列级的操作权限。

  5. host 权限表:配合 db 权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT 和 REVOKE 语句的影响。

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

PDF 出处:第 73–73 页 · 原卷分组:mysql · 源标题 p073-h05。

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

  1. statement 模式下,每一条会修改数据的 SQL 都会记录在 Binlog 中。不需要记录每一行的变化,减少了 Binlog 日志量,节约了 IO,提高性能。由于 sql 的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制。

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

  3. mixed,一种折中的方案,普通操作使用 statement 记录,当无法使用 statement 的时候使用 row

MySQL 存储引擎 MyISAM 与 InnoDB 区别 ​

PDF 出处:第 73–74 页 · 原卷分组:mysql · 源标题 p073-h06。

  1. 锁粒度方面:由于锁粒度不同,InnoDB 比 MyISAM 支持更高的并发;InnoDB 的锁粒度为行锁、 MyISAM 的锁粒度为表锁、行锁需要对每一行进行加锁, 73 所以锁的开销更大,但是能解决脏读和不可重复读的问题,相对来说也更容易发生死锁

  2. 可恢复性上:由于 InnoDB 是有事务日志的,所以在产生由于数据库崩溃等条件后,可以根据日志文件进行恢复。而 MyISAM 则没有事务日志。

  3. 查询性能上:MylSAM 要优于 InnoDB 因为 InnoDB 在查询过程中,是需要维护数据缓存,而且查询过程是先定位到行所在的数据块,然后在从数据块中定位到要查找的行;而 MyISAM 可以直接定位到数据所在的内存地址,可以直接找到数据。

  4. 表结构文件上:MyISAM 的表结构文件包括:frm(表结构定义),.MYI(索引),.MYD(数据);而 InnoDB 的表数据文件为:ibd 和 frm(表结构定义)。

MyISAM 索引与 InnoDB 索引的区别? ​

PDF 出处:第 74–74 页 · 原卷分组:mysql · 源标题 p074-h01。

  1. InnoDB 索引是聚簇索引,MyISAM 索引是非聚簇索引。

  2. InnoDB 的主键索引的叶子节点存储着行数据,因此主键索引非常高效。

  3. MyISAM 索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。

  4. InnoDB 非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效。

什么是索引 ​

PDF 出处:第 74–74 页 · 原卷分组:mysql · 源标题 p074-h02。

索引是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用 B 树及其变种 B+树。更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。

索引有哪些优缺点 ​

PDF 出处:第 74–74 页 · 原卷分组:mysql · 源标题 p074-h03。

索引的优点

  1. 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。

  2. 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

索引的缺点

  1. 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;

  2. 空间方面:索引需要占物理空间

索引有哪几种类型? ​

PDF 出处:第 74–75 页 · 原卷分组:mysql · 源标题 p074-h04。

主键索引:数据列不允许重复,不允许为 NULL,一个表只能有一个主键。唯一索引:数据列不允许重复,允许为 NULL 值,一个表允许多个列创建唯一索引。

  1. 可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引。

  2. 可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引。

普通索引:基本的索引类型,没有唯一性的限制,允许为 NULL 值。

  1. 可以通过 ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引

  2. 可以通过 ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引。全文索引:是目前搜索引擎使用的一种关键技术。

  3. 可以通过 ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引。

MySQL 中有哪几种锁? ​

PDF 出处:第 75–75 页 · 原卷分组:mysql · 源标题 p075-h01。

  1. 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

  2. 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

  3. 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别? ​

PDF 出处:第 75–75 页 · 原卷分组:mysql · 源标题 p075-h02。

  1. SQL 标准定义的四个隔离级别为:

  2. read uncommited:读到未提交数据

  3. read committed:脏读,不可重复读

  4. repeatable read:可重读

  5. serializable:串行事物

char 和 varchar 的区别? ​

PDF 出处:第 75–75 页 · 原卷分组:mysql · 源标题 p075-h03。

  1. char 和 varchar 类型在存储和检索方面有所不同

  2. char 列长度固定为创建表时声明的长度,长度值范围是 1 到 255

  3. 当 char 值被存储时,它们被用空格填充到特定长度,检索 char 值时需删除尾随空格。

主键和候选键有什么区别? ​

PDF 出处:第 75–75 页 · 原卷分组:mysql · 源标题 p075-h04。

表格的每一行都由主键唯一标识,一个表只有一个主键。主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键引用

如何在 Unix 和 MySQL 时间戳之间进行转换? ​

PDF 出处:第 75–75 页 · 原卷分组:mysql · 源标题 p075-h05。

UNIX_TIMESTAMP 是从 MySQL 时间戳转换为 Unix 时间戳的命令 FROM_UNIXTIME 是从 Unix 时间戳转换为 MySQL 时间戳的命令

MyISAM 表类型将在哪里存储,并且还提供其存储格式? ​

PDF 出处:第 75–75 页 · 原卷分组:mysql · 源标题 p075-h06。

每个 MyISAM 表格以三种格式存储在磁盘上:

  1. “.frm”文件存储表定义

  2. 数据文件具有“.MYD”(MYData)扩展名

  3. 索引文件具有“.MYI”(MYIndex)扩展名

MySQL 里记录货币用什么字段类型好 ​

PDF 出处:第 76–76 页 · 原卷分组:mysql · 源标题 p076-h01。

NUMERIC 和 DECIMAL 类型被 MySQL 实现为同样的类型,这在 SQL92 标准允许。他们被用于保存值,该值的准确精度是极其重要的值,例如与金钱有关的数据。当声明一个类是这些类型之一时,精度和规模的能被(并且通常是)指定。例如: salary DECIMAL(9,2) 在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而 2(scale)代表将被用于存储小数点后的位数。因此,在这种情况下,能被存储在 salary 列中的值的范围是从-9999999.99 到 9999999.99。

创建索引时需要注意什么? ​

PDF 出处:第 76–76 页 · 原卷分组:mysql · 源标题 p076-h02。

  1. 非空字段:应该指定列为 NOT NULL,除非你想存储 NULL。在 MySQL 中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。应该用 0、一个特殊的值或者一个空串代替空值;

  2. 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;

  3. 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次 I/O 操作获取的数据越大效率越高

使用索引查询一定能提高查询的性能吗?为什么 ​

PDF 出处:第 76–76 页 · 原卷分组:mysql · 源标题 p076-h03。

通常,通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价。索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改。这意味着每条记录的INSERT,DELETE,UPDATE 将为此多付出 4,5 次的磁盘 I/O。因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能,索引范围查询(INDEX RANGE SCAN)适用于两种情况:

  1. 基于一个范围的检索,一般查询返回结果集小于表中记录数的 30%

  2. 基于非唯一性索引的检索

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

PDF 出处:第 76–76 页 · 原卷分组:mysql · 源标题 p076-h04。

关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的 IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询 MySQL 官方手册得知删除数据的速度和创建的索引数量是成正比的。

  1. 所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)

  2. 然后删除其中无用数据(此过程需要不到两分钟)

  3. 删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。

  4. 与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。那更是坑了。

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

PDF 出处:第 76–76 页 · 原卷分组:mysql · 源标题 p076-h05。

顾名思义,就是最左优先,在创建多列索引时,要根据业务需求,where 子句中使用最频繁的一列放在最左边。最左前缀匹配原则,非常重要的原则,MySQL 会一直向右匹配直到遇到范围查询(>、<、 between、like)就停止匹配,比如 a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立 (a,b,d,c)的索引则都可以用到,a,b,d 的顺序可以任意调整。 =和 in 可以乱序,比如 a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,MySQL 的查询优化器会帮你优化成索引可以识别的形式。

什么是聚簇索引?何时使用聚簇索引与非聚簇索引 ​

PDF 出处:第 77–77 页 · 原卷分组:mysql · 源标题 p077-h01。

  1. 聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据

  2. 非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam 通过 key_buffer 把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在 key buffer 命中时,速度慢的原因。

MySQL 连接器 ​

PDF 出处:第 77–77 页 · 原卷分组:mysql · 源标题 p077-h02。

首先需要在 MySQL 客户端登陆才能使用,所以需要个连接器来连接用户和 MySQL 数据库,我们一般是使用 mysql-u 用户名-p 密码来进行 MySQL 登陆,和服务端建立连接。在完成 TCP 握手后,连接器会根据你输入的用户名和密码验证你的登录身份。如果用户名或者密码错误,MySQL 就会提示 Access denied for user,来结束执行。如果登录成功后,MySQL 会根据权限表中的记录来判定你的权限。

MySQL 查询缓存 ​

PDF 出处:第 77–77 页 · 原卷分组:mysql · 源标题 p077-h03。

连接完成后,你就可以执行 SQL 语句了,这行逻辑就会来到第二步:查询缓存。 MySQL 在得到一个执行请求后,会首先去查询缓存中查找,是否执行过这条 SQL 语句,之前执行过的语句以及结果会以 key-value 对的形式,被直接放在内存中。key 是查询语句,value 是查询的结果。如果通过 key 能够查找到这条 SQL 语句,就直接妾返回 SQL 的执行结果。如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果就会被放入查询缓存中。可以看到,如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,效率会很高。

MySQL 分析器 ​

PDF 出处:第 77–77 页 · 原卷分组:mysql · 源标题 p077-h04。

如果没有命中查询,就开始执行真正的 SQL 语句。

  1. 首先,MySQL 会根据你写的 SQL 语句进行解析,分析器会先做词法分析,你写的 SQL 就是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符串是什么,代表什么。

  2. 然后进行语法分析,根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个 SQL语句是否满足 MySQL 语法。如果 SQL 语句不正确,就会提示 You have an error in your SQL syntax

MySQL 优化器 ​

PDF 出处:第 77–77 页 · 原卷分组:mysql · 源标题 p077-h05。

经过分析器的词法分析和语法分析后,你这条 SQL 就合法了,MySQL 就知道你要做什么了。但是在执行前,还需要进行优化器的处理,优化器会判断你使用了哪种索引,使用了何种连接,优化器的作用就是确定效率最高的执行方案

MySQL 执行器 ​

PDF 出处:第 77–77 页 · 原卷分组:mysql · 源标题 p077-h06。

MySQL 通过分析器知道了你的 SQL 语句是否合法,你想要做什么操作,通过优化器知道了该怎么做效率最高,然后就进入了执行阶段,开始执行这条 SQL 语句在执行阶段,MySQL 首先会判断你有没有执行这条语句的权限,没有权限的话,就会返回没有权限的错误。如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。对于有索引的表,执行的逻辑也差不多。

什么是临时表,何时删除临时表? ​

PDF 出处:第 78–78 页 · 原卷分组:mysql · 源标题 p078-h01。

什么是临时表?MySQL 在执行 SQL 语句的过程中通常会临时创建一些存储中间结果集的表,临时表只对当前连接可见,在连接关闭时,临时表会被删除并释放所有表空间。临时表分为两种:一种是内存临时表,一种是磁盘临时表,什么区别呢?内存临时表使用的是 MEMORY 存储引擎,而临时表采用的是MylSAM 存储引擎。 MySQL 会在下面这几种情况产生临时表。

  1. 使用 UNION 查询:UNION 有两种,一种是 UNION,一种是 UNION ALL,它们都用于联合查询;区别是使用 UNION 会去掉两个表中的重复数据,相当于对结果集做了一下去重(distinct)。使用UNIONALL,则不会排重,返回所有的行。使用 UNION 查询会产生临时表。

  2. 使用 TEMPTABLE 算法或者是 UNION 查询中的视图。TEMPTABLE 算法是一种创建临时表的算法,它是将结果放置到临时表中,意味这要 MySQL 要先创建好一个临时表,然后将结果放到临时表中去,然后再使用这个临时表进行相应的查询。

  3. ORDER BY 和 GROUPBY 的子句不一样时也会产生临时表。

  4. DISTINCT 查询并且加上 ORDER BY 时;

  5. SQL 中用到 SQL_SMALL_RESULT 选项时;如果查询结果比较小的时候,可以加上 SQL SMALL RESULT 来优化,产生临时表

  6. FROM 中的子查询;

  7. EXPLAIN 查看执行计划结果的 Extra 列中,如果使用 Using Temporary 就表示会用到临时表

谈谈 SQL 优化的经验 ​

PDF 出处:第 78–78 页 · 原卷分组:mysql · 源标题 p078-h02。

  1. 查询语句无论是使用哪种判断条件等于、小于、大于,WHERE 左侧的条件查询字段不要使用函数或者表达式

  2. 使用 EXPLAIN 命令优化你的 SELECT 查询,对于复杂、效率低的 SQL 语句,我们通常是使用explainsql 来分析这条 SQL 语句,这样方便我们分析,进行优化。

  3. 当你的 SELECT 查询语句只需要使用一条记录时,要使用 LIMIT 1。不要直接使用 SELECT*,而应该使用具体需要查询的表字段,因为使用 EXPLAIN 进行分析时,SELECT"使用的是全表扫描,也就是 type =all。

  4. 为每一张表设置一个 ID 属性。

  5. 避免在 MHERE 字句中对字段进行 NULL

  6. 判断避免在 WHERE 中使用!或>操作符

  7. 使用 BETWEEN AND 替代 IN

  8. 为搜索字段创建索引

  9. 选择正确的存储引擎,InnoDB、MyISAM、MEMORY 等

  10. 使用 LIKE%abc%不会走索引,而使用 LIKE abc%会走索引。

  11. 对于枚举类型的字段(即有固定罗列值的字段),建议使用 ENUM 而不是 VARCHAR,如性别、星期、类型、类别等。

  12. 拆分大的 DELETE 或 INSERT 语句

  13. 选择合适的字段类型,选择标准是尽可能小、尽可能定长、尽可能使用整数。

  14. 字段设计尽可能使用 NOT NULL

  15. 进行水平切割或者垂直分割

什么叫外链接? ​

PDF 出处:第 79–79 页 · 原卷分组:mysql · 源标题 p079-h01。

外连接分为三种,分别是是左外连接(LEFT OUTER J0IN 或 LEFT JOIN 右外连接(RIGHT OUTER JOIN 或RIC GHT JOIN、全外连接(FULL OUTER JOIN 或 FULLJOIN)。左外连接:又称为左连接,这种连接方式会显示左表不符合条件的数据行,右边不符合条件的数据行直接显示 NULL。右外连接:也被称为右连接,他与左连接相对,这种连接方式会显示右表不符合条件的数据行,左表不符合条件的数据行直接显示NULL

什么叫内链接? ​

PDF 出处:第 79–79 页 · 原卷分组:mysql · 源标题 p079-h02。

结合两个表中相同的字段,返回关联字段相符的记录就是内链接

使用 union 和 union all 时需要注意些什么? ​

PDF 出处:第 79–79 页 · 原卷分组:mysql · 源标题 p079-h03。

通过 union 连接的 SQL 分别单独取出的列数必须相同。使用 union 时,多个相等的行将会被合并,由于合升比较耗时,一般不直接使用 union 进行合并,而是通常采用 union all 进行合并。

MyISAM 存储引擎的特点 ​

PDF 出处:第 79–79 页 · 原卷分组:mysql · 源标题 p079-h04。

在 5.1 版本之前,MyISAM 是 MySQL 的默认存储引擎,MylSAM 并发性比较差,使用的场景比较少主要特点是:

  1. 不支持事务操作,ACID 的特性也就不存在了,这一设计是为了性能和效率考虑的,

  2. 不支持外键操作,如果强行增加外键,MySQL 不会报错,只不过外键不起作用。

  3. MyISAM 默认的锁粒度是表级锁,所以并发性能比较差,加锁比较快,锁冲突比较少,不太容易发生死锁的情况。

  4. MyISAM 会在磁盘上存储三个文件,文件名和表名相同,扩展名分别是 frm(存储表定义)、 MYD(MYData,存储数据)、MYI(MyIndex,存储索引)。这里需要特别注意的是 MyISAM 只缓存索引文件,并不缓存数据文件。

  5. MyISAM 支持的索引类型有全局索引(Full-Text)、B-Tree 索引、R-Tree 索引 Full-Text 索引:它的出现是为了解决针对文本的模糊查询效率较低的问题。 B-Tree 索引:所有的索引节点都按照平衡树的数据结构来存储,所有的索引数据节点都在叶节点 R-Tree 索引:它的存储方式和 B-Tree 索引有一些区别,主要设计用于存储空间和多维数据的字段做索引目前的 MySQL 版本仅支持geometry 类型的字段作索引,相对于 BTREE,RTREE 的优势在于范围查找。

  6. 数据库所在主机如果宕机,MyISAM 的数据文件容易损坏,而且难以恢复。

  7. 增删改查性能方面:SELECT 性能较高,适用于查询较多的情况

InnoDB 存储引擎的特点 ​

PDF 出处:第 79–80 页 · 原卷分组:mysql · 源标题 p079-h05。

自从 MySQL5.1 之后,默认的存储引擎变成了 InnoDB 存储引擎,相对于 MylSAM,InnoDB 存储引擎有了较大的改变,它的主要特点是

  1. 支持事务操作,具有事务 ACID 隔离特性,默认的隔离级别是可重复读 (repetable-read)、通过MVCC(并发版本控制)来实现的。能够解决脏读和不可重复读的问题。 InnoDB 支持外键操作。

  2. InnoDB 默认的锁粒度行级锁,并发性能比较好,会发生死锁的情况。

  3. 和 MyISAM 一样的是,InnoDB 存储引擎也有 frm 文件存储表结构定义,但是不同的是,InnoDB的表数据与索引数据是存储在一起的,都位于 B+数的叶子节点上,而 MylSAM 的表数据和索引数据是分开的。

  4. InnoDB 有安全的日志文件,这个日志文件用于恢复因数据库崩溃或其他情况导致的数据丢失问题,保证数据的一致性。

  5. InnoDB 和 MylSAM 支持的索引类型相同,但具体实现因为文件结构的不同有很大差异。

  6. 增删改查性能方面,果执行大量的增删改操作,推荐使用 InnoDB 存储引擎,它在删除操作时是对行删除,不会重建表。