1.如何设计一个数据库
首先得有两部分:
1)存储(文件系统):用于存储数据到硬盘中;
2)程序实例:通知程序把数据存储到文件系统中,程序实例由大致的8个模块组成:
2.一个请求进来, mysql是怎么运行工作的
1,当我们执行启动 MySQL 命令之后,MySQL 初始化整个系统,同时各个存储引擎也被启动,当整个系统初始化结束后,由连接管理模块接手。准备好接受客户端请求了。
2, 当连接管理模块监听到客户端的连接请求(借助网络交互模块的相关功能)连接管理模块就会将连接请求转发给线程管理模块,去请求一个连接线程。线程管理模块马上又会将控制交给连接线程模块,告诉连接线程模块:现在我这边有连接请求过来了,需要建立连接,连接线程池中如果有空闲连接线程,就取出一个和客户端请求连接上,如果没有空闲的连接线程,则建立一个新的连接线程与客户端请求连接。
3, 在 MySQL 中,将客户端请求分为了两种类型:一种是 query,需要调用Query 解析和转发模块的解析才能够执行的请求;一种是 command,可以直接执行的请求。如果我们的初始化配置中打开了日志的功能,那么Query 解析与转发模块会调用日志记录模块将请求计入日志,不管是一个 Query 类型的请求还是一个 command 类型的请求,都会被记录进入日志,所以出于性能考虑,一般很少打开日志的功能。
4, 当客户端请求和连接线程接上之后,连接线程就开始处理客户端请求发送过来的各种命令(或者 query),接受相关请求。
5, 如果是一个 Query 类型的请求,会将控制权交给 Query 解析器。Query 解析器首先分析看是不是一个 select 类型的 query,如果是,则调用查询缓存模块,让它检查该 query 在query cache 中是否已经存在。如果有,则直接将 cache 中的数据返回给连接线程模块,然后通过与客户端的连接的线程将数据传输给客户端。如果 cache 中没有该 query 的数据,那么 query 将被继续传回 query 解析器,让 query解析器进行相应处理,再通过 query 分发器分发给相关处理模块。
6, 如果解析器解析结果是一条未被 cache 的 select 语句,则将控制权Query 优化器模块,如果是 DML 或者是 DDL 语句,则会交给表变更管理模块,还有其他模块这里不一一说明;
7, 在各个模块收到 Query 解析与分发模块分发过来的请求后,就会调用表管理模块请求相应的表,并获取对应的锁。然后将打开的表交给表变更管理模块。
8, 当表变更管理模块“获取”打开的表之后,调用对应的存储引擎实现模块,进行相应处理。
9, 当一条 query 或者一个 command 处理完成(成功或者失败)之后,控制权都会交还给连接线程模块。如果处理成功,则将处理结果(可能是一个 Result set,也可能是成功或者失败的标识)通过连接线程反馈给客户端。如果处理过程中发生错误,也会将相应的错误信息发送给客户端,然后连接线程模块会进行相应的清理工作,并继续等待后面的请求,重复上面提到的过程,或者完成客户端断开连接的请求。
3.什么是回表?
一个查询中,如果查询条件为二级索引,如下图的name条件, 匹配到 name 后,再根据name去查询另一个B+ 树,这就是回表, 如下图 Innodb 二级索引查询流程,存在回表问题。
4.不同引擎的索引效率区别
Innodb 用主索引查询的时候会比 myisam 快, 因为主索引查询的时候, Innodb 他的索引和数据是放在一个文件夹的,myisam 二级索引查询的时候会比 Innodb 的二级索引查询要快, 他虽然要根据叶子节点的地址去查询另一个文件 myd 里的data数据, 但是他没有回表的操作, 所以用二级索引查询的时候 myisam 比 Innodb 要快。
5.给字段添加索引需要注意什么?
0:读比写多很多的情况下, 才要去加索引;
1:较频繁的作为查询条件的字段应该创建索引;
2:唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件;
3:更新非常频繁的字段不适合创建索引;
4:不会出现在WHERE 子句中的字段不该创建索引;
6.explain 命令有什么用?
MySQL的 EXPLAIN 命令用于 SQL 语句执行计划的查询。这条命令的输出结果能够让我们了解MySQL 优化器是如何执行 SQL 语句的。这条命令并没有提供任何调整建议,但它能够提供重要的信息帮助你做出调优决策。
7.profiling 命令有什么用?
能够查出最近执行的SQL语句的运行状态,包括在运行过程中执行了哪些操作,各占用了多少时间,利用proflie 功能,可以分析一个SQL具体的执行代价是怎么样的,尤其是可以分析它的最大瓶颈在哪里。目前profile 功能可提供除了内存以外的其他资源消耗统计,例如CPU、I/O、CONTEXT、SWAP等。大部分情况下,profile 的结果我们主要关注两列:Status、Duration,前者表示的是profile 里的状态,后者是该状态的耗时。因此,我们最主要的是关注处于哪个状态耗时最久,这些状态中,哪些是可以进一步优化的。
8.join 的原理
8.1.Simple Nested-Loop join:(简单嵌套循环)
简单嵌套循环连接实际上就是简单粗暴的嵌套循环, 如果外层表table1有1万条数据, 内层表table2有1万条数据, 那么所有数据比较的次数就是1w乘以1W=1亿, 这种查询是非常慢的;
**优化:**利用小的结果集驱动大的结果集,减少对内层表(table2)的访问, 就是访问的表的数据要小于被访问表的数据;这种方式在查询优化器里他默认已经帮我们做了,不需要我们自己去做
虽然可以像上面这么去优化, 但就算优化了, 数据量大的话他的查询速度还是很慢的,
8.2.index Nested-Loop join:(索引嵌套循环,性能最高)
这种方式他在连表的时候不是直接去连table2表, 而是去找table2 的索引,这种方式就要比Simple快的多, 因为被驱动的表的查询数变少了, 所以我们在join表的时候, 被join的字段尽量要加上索引,减少内层表数据的匹配次数;
索引嵌套循环连接是基于索引进行连接的算法,索引是基于内层表的,通过外层表匹配条件直接与内层表索引进行匹配,避免和内层表的每条记录进行比较, 从而利用索引的查询减少了对内层表的匹配次数,优势极大的提升了 join的性能:
原来的匹配次数 = 外层表行数 * 内层表行数
优化后的匹配次数= 外层表的行数 * 内层表索引的高度
8.3.Block Nested-Loop join:(缓存块嵌套循环)
这里有一个join buffer 他相当于一个缓冲区,以前只能让表1一个一个的去访问表2,现在有了缓冲区,可以同时多个表1的数据去访问表2,访问次数减少了,以前六个数据,每一个都要去访问表二,所以要访问6次,现在有了join buffer,他是每次三个数据一起去访问,那么总共6个数据,只需要访问2次就完成了;




