1 、我创建了⼀个没有select权限的⽤户, 执⾏select * from T where k=1 , 报错“select command denied”,并没有报错“unknown column”,是不是可以说明是在打开表之后才判断读取的列不存在?
答:这个是⼀个安全⽅⾯的考虑。你想想⼀个⽤户如果没有查看这个表的权限,你是会告诉他字段不对还是没权限?如果告诉他字段不对,其实给的信息太多了,因为没权限的意思还包含了: 没权限知道字段是否存在。
2、wait_timeout 是客户端 ⾮交互式的连接时间,如果程序连接mysql SERVER,是交互连接, 关联的时间参数为interactive_timeout, 这两个时间参数需要尽量⼀致吗,⼀般设置多少合适?
query_cache_size 参数虽然不⽤了,我想确认下,关闭情况是 query_cache_size=0 要匹配参数
query_cache_type=off吗? 还是直接query_cache_size=0 即可?
答:第⼀个问题:是的,这两个尽量设置成相同。值的话取决于业务。如果你⾯对的是成熟的开发(⽐如公司内部团队),可以设置⼩些,分钟级别就⾏。
第⼆个问题:这两个都可以,不过⽤query_cache_type会好些(代码判断路径更短) 。
3、⽂⾥遇到临时内存会跟随⻓连接的存在⽽存在,直到连接被销毁。想问的是,这部分临时内 存是由于什么产⽣?为什么不提前释放呢?mysql有⽤到内存池吗?
答:排序、变量这些会占⽤内存,如果要复⽤,以前释放反⽽影响性能,MySQL没法⾃⼰决定,所以5.7之后提供了⽅法让客户端有命令来做;MySQL的内存池⼀般说的是查询缓存和引擎
⾥⾯的(⽐如InnoDB 的buffe pool), 跟线程内缓存不是⼀个概念。
4、⽂中join的例⼦,内表和外表 都有⾼区分度条件的情况下,先过滤出两表符合条件的记录, 再对这些记录做join,可不可以?感觉这样性能更⾼。
答:MySQL确实有你提到的这种算法,叫做index_merge. 不过我们这个case⾥⾯不会,由于实现的原因,MySQL⾄今没有⽀持跨表index_merge。
5、末尾问题有个疑问。是在分析器⾥⾯检查的列是否存在。且⽂章中说到执⾏器会检查有没有 权限。那为什么⼀个没有查询权限的⽤户进⾏查询语句,提示的是"没有权限"⽽不是"列不存 在"。按照这个逻辑权限应该是在执⾏器做的,那这个"权限不存在"是哪个模块检查的?
答:查询的时候权限不存在是在执⾏前单独多的⼀次判断,是为了安全考虑。就是如果没有权 限,你连“字段不存在”这个信息都不应该暴露给客户端。
6、如果你⽤的是 MySQL 5.7 或更新版本,可以在每次执⾏⽐较⼤的操作, 请问⽐较⼤的操作的判断维度是什么呢? 即怎么判断是⽐较⼤的操作?
答:其实就是类似于很多数据排序,或者⼀个操作复杂的存储过程。这个是可以在测试环境稳定复现的。 如果语句都差不多,或者⽐较随机,或者可以⽤另外⼀种⽅法,⽐如⼀个连接执⾏了
N个语句以后做reset这个动作。
7、既然在链接阶段已经通过权限表获取了这个该连接所具有的权限,那么在执⾏阶段再检查⼀ 次的意义何在?
答:执⾏器阶段会碰到需要再判断权限的情况,这时候读内存中事先存好的权限,⽽这个权限是在连接器阶段算出来存进去的。
8、请教个业务操作表的场景,如果对⼀个业务数据表的操作既有查询(分⻚查询批处理),⼜ 有更新,此场景下都是操作主库好呢?还是说查询⾛从库,更新操作⾛从库?您有没有好的建议呢,如果遇到了此类业务场景您会怎么分析解决此困扰呢?
答:必须做语句分类,延迟敏感的⾛主库,不敏感的⾛从库。
9、上⾯说如果开启缓存查询在不命中的情况下开始执⾏分析器,分析语句,那么我发送语句的
key是什么时候⽣成的还是直接拿语句作为key,这时候我过我语句的列中包含了错误的列名在这个阶段是不检查的吗?
答:就是语句做key, 这时候还没到分析器阶段,确实还没检查。 不过不影响逻辑正确性,你分析的时候要带上失效逻辑哈。
10、我们有什么办法实时获取⽬前已查询到多少⾏的数据了?⽐如我⽤php语⾔怎么调⽤
rows_examined实时获取查询的进度?
答:查询进度是没有的,如果是查询结束后,看查到多少⾏,就是MySQL_num_rows. 不过这个跟rows_examined不⼀样哦。
11、权限为什么不在句法分析之前呢,此时已经完成了词法分析,知道了查询的表和列了,完 全可以分析。
答:执⾏过程可能会有触发器这些,还是得到这⼀步才判断。 但是为了安全,有⼀个precheck 会在优化器之前判断⼀下权限。
12、关于在连接器⽅⾯,在连接器中怎样给新的连接归类为⻓连接还是短连接的,判断的标准 是什么?
答:不⽤判断,连接建⽴成功后就是连接,断开就是断开。只是我们建议减少创建连接到次数。
13、⽂中说明权限判断是在执⾏器中进⾏的,那么假如查询的语句命中了查询缓存,按流程就 直接返回了,那这种情况权限判断是怎么处理的呢?
答:从query_cache查到结果后,结果⾥⾯有表的信息,要做权限验证的,权限不够还是报错处 理。
14、c mysql接⼝连接设置好mysql_ping⾃动重连之后。查询时候会⾃动调⽤吗?还是要⾃⼰主动定时检测。
答:虽然会⾃动了,但是如果是程序⾥有⽤到事务,还是需要处理的,否则事务被拆成两个(前
⾯⼀半⾃动回滚)业务还不知道,也不是好事哦。
15、在mysql中的多字段模糊查询同⼀个值!怎么写的执⾏效率⾼?
答:MySQL ⽀持全⽂检索(fulltext index)的,⽐顺序遍历快,不过相⽐于ES这样的系统,
MySQL 的全⽂检索能⼒还是有待加强。
16、“MySQL 在执⾏过程中临时使⽤的内存是管理在连接对象⾥⾯的”
请问 “管理在连接对象⾥⾯” 这个怎么理解呢?是还有管理在其它什么地⽅的吗?是因为管理在对象⾥⾯才会被 OOM 的吗?
答:每个连接对应⼀个THD对象,这些内容都在这个对象⾥。
17、关于不建议⽤查询缓存的,虽然查询缓存命中率很低,但是⼀旦命中不是就能减少查询时 间吗。不使⽤查询缓存是能节省去查询缓存中匹配查询的流程,还有什么其它好处吗?从你说的内容中我还不是很明⽩不⽤查询缓存带来了什么好处?
答:不是,不使⽤查询缓存就不需要维护,就是查到结果不⽤写到查询缓存去,这个才是最⼤的收益哦。
18、查询缓存的时候需要执⾏select语句,这个时候不需要经过分析器对语法词法进⾏分析吗? 答:查询缓存不是”select语句”,是查询内部的⼀个数据结构。
19、java⽤jdbc或者mybatis连接数据库,对于定时任务(每天执⾏⼀次),连接器会在8⼩时
⾃动断开链接?那每天执⾏的时候是重新获取连接?
答:你要看下这个客户端的代码实现。看看他是不是⾃⼰会重新获得连接,或者是不是会维持⼼跳。
20、Write-Ahead Logging-先写⽇志再写磁盘,空闲的时候写⼊磁盘。那么如何判别空闲呢? 假如我增加⼀条数据 ,⽽这条数据只写⼊了⽇志 ,还没来得及写进磁盘,⽽我还要读取刚写⼊的这条数据怎么办呢?
答:读内存。⾄于空闲,系统有判断规则的,⽐如QPS这类。
21、问题1:
在缓存开启状态下, 要判别sql是select还是其他类型,保证只有select才去查询缓存,那么这个判断操作是何时进⾏的呢? 我猜测在查询缓存之前, 但是分析器也要对sql关键字进⾏分析,再分析⼀遍岂不是重复? 因为我没有看源码,所以这⼀块不明⽩, 如果我来设计的话, 可能是把查询缓存这个模块在分析器阶段来执⾏, 由分析器进⾏关键字解析,判断是何种sql语句,如果是select, 再去查询缓存, 如果不是继续往下进⾏好像更合理,看到⼤家都说先查询缓存,没有命中再去分析器, 感觉不太通。
问题2:
在mysql中通过“explain extended和show warnings”命令来查看的sql, 是不是优化器重写之后的sql? 以前我看到⼀本书中提到,也可能是⼀篇博客,mysql的单表的union查询其实会优化成or查询, 但是show warnings看到的还是union查询语句,所以有此疑问。
问题3:
update等sql清空缓存是在sql执⾏完返回结果给客户端之前还是之后, 还是说同时进⾏的, 会不会存在清空缓存失败, 但是告诉客户端update success, 缓存的地⽅⼀直不是很清楚, 所以正好 will be removed in a future releas, 真是⼀个⼤快⼈⼼。
答:1. 实际上肯定是要判断出是select语句, 但是之后的解析都没做哈。 要理解成“包含在内”也可以。
2.Show wanings不会把重写后的显示出来,只是格式化后。
3.清空缓存失败这个不太可能,这个内部结构的操作没什么依赖。
22、数据库所在的docker配了80G内存。但因数据库配置⽂件⾥的参数配置不好,通过计算, 达到了1024G,⽽,现在已经到达容器内存100%了。之后我把参数改到合理值,但内存还没 降,应该是保持会话的没⽣效,新会话⽣效了。现在数据库不能重启,也不能把会话都kill掉。要怎么处理才能使内存降下来的?
答:会话不能kill? 这样程序应该升级,正常的程序要能够处理异常连接连接断开哦。
23、如果⽤户名密码认证通过,连接器会到权限表⾥⾯查出你拥有的权限和执⾏阶段去查询有 没有select的权限这两个有什么区别?
答:连接器阶段是去系统表读数据,结果放在变量;执⾏器使⽤这个变量。
24、⽂中写到,执⾏器会调⽤引擎提供的借⼝查询数据。是不是可以认为,最终遍历数据是引 擎来完成当的。
答:“遍历”这个动作是执⾏器让做的,引擎给了两个接⼝:取第⼀个、取下⼀个。
25、⽂章提到:
1.建⽴连接成功之后,在连接器阶段会先到查询缓存查看是否存在该 SQL 的缓存。
2.针对⼀条 SQL 语句,在分析器的词法分析阶段,从关键字 select 中识别出是⼀条查询语句。
这⾥有⼀个疑问,在分析器阶段才识别出 SQL 是查询语句,⽽在连接器阶段,如何决定是否需要到查询缓存看看呢?
答:嗯,确实是“识别出这个是⼀个查询缓存”这个动作是在连接器之后,查询缓存之前的,但是在查询缓存之前也只做了这⼀步⼩⼩的解析哈。
26、MySQL的连接池就是把⽤完的链接放回池⼦⾥,给别的业务线程复⽤,变短链接为⻓链接。
MySQL的连接池是在InnoDB 的buffe pool⾥⾯的吗?和MySQL企业版的thread_pool的实现原理类似吗?
答:1. 不是,连接池是server层的。
2. Thread_pool是线程池,给不同的连接复⽤线程;连接池是复⽤连接。
27、MySQL 拿到⼀个查询请求后,会先到查询缓存看看,之前是不是执⾏过这条语句。之前执
⾏过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。
⽼师请问关于上⾯的这段,如果执⾏语句相同,仅仅是条件不同,会⾛查询缓存么? 如 :select * from user where id=6
select * from user where id=7 这两句.
答:不会,查询缓存要求语句⼀摸⼀样才⾏,别说你这个参数变了,就算两个语句差异只是多⼀个空格都不⾏哦。
28、时间区间查询,between and跟<=>=有性能差异吗? 答:没有,不⽌时间区间,所有类型这两个都是等价操作。
29、执⾏器去操作引擎获取数据的时候,因为引擎查询数据也需要时间,那执⾏器是不是有个 等待的过程?您说的rows_examined是记录执⾏器每调⽤引擎获取数据刚时累加,那是不是可以这样理解在⼀个查询过程中,执⾏器会间隔⼀段时间去引擎获取数据?如果是这种的话,我⼜有⼀个疑问了,执⾏器怎么知道引擎已经查询完了,最终返回数据的呢?
答:不是。执⾏器是同步调⽤引擎接⼝,不是异步调⽤。执⾏过程中累计的。
30、问题1:和其他同学有类似的疑问:关于没有权限操作表的时候的报错:
如果分析器已经知道了“unknown column” 之后, 为什么还会报错: “select command
denied”。你之前的回答是:由于安全考虑,⽤户没有权限操作这个表,那么也不需要告诉⽤户这么多,直接告诉⽤户没有权限。
【重点疑问】如果是按照这样的话,且对表的权限检查都在执⾏器的话,那么每个sql在执⾏的时候⾄少都会执⾏到执⾏器吗?
因为同时看到⽂中在执⾏器章节:于是就进⼊了执⾏器阶段,开始执⾏语句。开始执⾏的时候, 要先判断⼀下你对这个表 T 有没有执⾏查询的权限,如果没有,就会返回没有权限的错误,如下所示。
SELECT command denied to user ‘b’@‘localhost’ for table ‘T’ 。
问题2:两位测试结果不⼀样,A的测试结果是Complete optimizer trace;B从他的描述来看, 测试结果应该是分析器。没有本项⽬上的MySQL权限,等明天⾃⼰本地版下好后,测试下结果。
答:1. 不是的,由于⼯程实现的原因,会有前置检查。
2. 这个也类似,其实如果看调⽤路径,执⾏器阶段都在mysql_parse函数⾥⾯调⽤的。 做这些阶段的拆分我觉得主要是⽅便我们从概念上理解,⼯程实现的时候确实不是1234这么按部就班 的。
31、执⾏ mysql_reset_connection 来重新初始化连接资源,我想请问下,如果在主从DB服务器执⾏这个操作会影响主从同步吗?
答:不会,这个操作没有写binlog,只是更新连接的线程内部数据。
32、“在⼯程实现上,如果命中查询缓存,会在查询缓存放回结果的时候,做权限验证。查询也会在优化器之前调⽤ precheck 验证权限。”不是很理解这块。
1.命中查询缓存之前在连接阶段不是已经做过权限验证了吗,为什么查询缓存放回结果的时候要再做权限验证。
2.优化器之前调⽤ precheck 验证权限和执⾏阶段的权限验证有何区别。
答:1. 连接阶段只是“获得权限信息”, 真正开始查询动作,才判断“有没有操作这个表的权限”
。
2. 不同的阶段, 执⾏器阶段是判断⼀些关联操作,⽐如更新⼀⾏的时候,由于触发器会再更新别的表,这种情况。
33、⽂中执⾏器模块给的例⼦sql是select * from ,引擎层返回了⼀整⾏数据,请问⽼师如果我只是select id from ,引擎层是只返回id⼀列,还是⼀整⾏。
答:只取id的话,引擎就只返回id给执⾏器。
34、怎样查看是⻓连接还是短连接,定期断开⻓连接怎样配置?另外最近做性能测试时发现⼤并 发⽤户同时连接MySQL时会有部分⽤户连接超时(设置的最⼤连接数1000,实际使⽤的最⼤连 接不会超过200),关于MySQL连接管理这块该怎样优化?
答:那你这个就是典型的短连接了,建议改成⻓链接⽅案。
35、为什么分析器完了还要⾛查询缓存?不是之前查询缓存没命中吗?查询缓存是在分析器阶 段之前的。
答:只是如果有更新语句,要去失效查询缓存。
36、MySQL 在执⾏过程中临时使⽤的内存是管理在连接对象⾥⾯的。这些资源会在连接断开的时候才释放。这⾥的内存是什么?不是BP,对吧。
答:是的,不是BP。 BP是在InnoDB⾥⾯维护的,只有InnoDB才;执⾏过程中的临时内存,是在连接对象⾥。
37、第⼀次调⽤的是“取满⾜条件的第⼀⾏”这个接⼝,之后循环取“满⾜条件的下⼀⾏”这个接
⼝,这些接⼝都是引擎中已经定义好的。这⾥⾯的接⼝怎么理解,我们在数据库中说的接⼝是什么。
答:这⾥的接⼝是指“引擎定义好的函数调⽤⽅法”,只是这个定义不是乱定义的,MySQL是⼀个插件式的结构,要求每个引擎以固定的⽅式提供调⽤⽅法。
38、skip-name-resolve这个参数是不是都需要配置优化呢,之前由于这个参数没有配置导致
sql查询特别慢,好多接⼝也因为这个响应时间特别⻓,请问⽼师域名解析是在连接器阶段吗? 还有这个参数是否为必须优化参数呢?
答:是在连接器阶段,建议全部设置为 skip-name-resolve。
39、mysql connection 内存占⽤过多,有没有办法在shell中看到具体的内存占⽤呢?
mysql_reset_connection 能不能再shell中执⾏?
答:官⽅版本还没有⽀持直接看内存消耗的,不能再shell执⾏的,是⼀个c的api。
40、请问⽼师,短连接和⻓连接是怎么设置的?是连接数据库的时候有什么参数吗?
答:不是,这是“⾏为”,⽐如连接完,执⾏⼀个查询,就断开,这是短连接;执⾏⼀个查询, 不断开,下次查询还⽤这个连接,持续使⽤,就是⻓链接。
41、短链接。 假设 代码执⾏2次select语句。每次都会重新建⽴连接吗? 答:这个是程序⾏为,看你程序怎么写的哈,也不⼀定就是2个。
⽐如以前⽤php写web⻚⾯,⼀个⻚⾯逻辑执⾏过程中⽤同同⼀个连接,这个⻚⾯⽤完就关掉连接。再刷新⻚⾯的时候再创建⼀个新连接,这个我也认为是短连接。
42、“输完命令之后,你就需要在交互对话⾥⾯输⼊密码。虽然密码也可以…”
如果是⽣产上⾯的数据库,为了查询,不在交互模式⾥直接输⼊密码,那么按照正确流程是如何进⾏连接的?场景是:在⽣产环境访问数据库。
发散⼀下,如果为了要养成良好习惯,我们在测试或者开发环境也不直接输⼊密码,那在测试或者开发环境怎样访问数据库是正确的?
答:1. 最好是在交互模式⾥⾯输⼊密码。
2. 对,测试或开发环境,最好也是交互模式⾥⾯输⼊密码。
43、逻辑架构图中,查询缓存有连接器和分析器两条线,是否说明有时候直接从连接器去查询缓 存查看是否命中,有时候会先经过分析器之后再去找查询缓存?如果是的话,为什么会有两种情况呢?缓存的key是⼀条sql语句吗?
答:分析器那条线是“更新”查询缓存。
44、MySQL 在执⾏过程中临时使⽤的内存是管理在连接对象⾥⾯的。 这句话啥意思? 答:就是说在线程断开的时候,内存肯定就会回收,不跟别的线程混⽤。
45、“数据库⾥⾯,⻓连接是指连接成功后,如果客户端持续有请求,则⼀直使⽤同⼀个连接。短连接则是指每次执⾏完很少的⼏次查询就断开连接,下次查询再重新建⽴⼀个。”想问下⻓连 接和短连接是不是⼈为的主观上来判断的,还是通过某些量化标准来定义的?
答:确实有主观成分,衡量标准就是“⼀次连接持续期间,执⾏了多少个sql语句”。
46、我可以认为redo log 记录的是这个⾏在这个⻚更新之后的状态,binlog 记录的是sql吗? Redo log不是记录数据⻚“更新之后的状态”,⽽是记录这个⻚ “做了什么改动”。
答:Binlog有两种模式,statement 格式的话是记sql语句, row格式会记录⾏的内容,记两条,更新前和更新后都有。
47、我想问下如果提交事务的时候正好重启那么redo log和binlog会怎么处理?此时redo log处于prepare阶段,如果不接受这条log,但是binlog已经接受,还是说binlog会去检查redo log的状态,状态为prepare的不会恢复?
答:Binlog如果已经接受,那么redolog是prepare, binlog已经完整了对吧,这时候崩溃恢复过程会认可这个事务,提交掉。 (你可以分析下这种情况下,是否符合我们要达到的“⽤binlog恢
复的库跟原库逻辑相同” 这个要求)。
48、有两个地⽅不太理解,⼀是,binlog也可以被引擎操作,那么binlog除了由执⾏器记录逻辑信息,是否引擎也会参与进binlog的记录?另外就是⼩结中提到的将log⽂件在磁盘中持久化, 这是⼀个怎样的操作?因为⼀想到外部磁盘总感觉和内存相⽐会很慢,每次更新都持久化磁盘会不会影响效率?
答:记录binlog这个动作是执⾏器做的,引擎会提供信息;写盘点代价⽐内存⾼的。但是这个是没法避免的。除⾮业务可以接受主机掉电丢数据。对于不能接受的业务,这个是绕不开的成 本。 所以幸好我们已经过了机械硬盘时代。
49、⽐如因为删表等操作需要回滚,但不希望数据库执⾏binlog中全部的语句 ⽐如说删除语句不执⾏的话 可以通过⾃⼰⼿动筛选数据库执⾏的binlog类型吗?还是必须都要执⾏呢?
答:可以在线程⾥⾯单独设置 是否使⽤binlog, 也可以单独设置binlog格式,前提是要有super 权限。
50、也就是说状态恢复的过程会去同时检查redo log和binlog?不然怎么能确定⼀个prepare的redo log已经写好了binlog,因为不检查的话不能确定到底是写好了binlog之后奔溃的还是写之前奔溃的,也就不能确定这个prepare log的合法性。如果检查的话那么不⽤两阶段提交好像也没什么问题,⽆论先写哪个⽇志都可以。
答:很好的思考,你考虑⼀下这个场景,redolog没写,binlog写好了,怎么算。 注意由于
binlog写完了,在备份恢复回来以后是会重放这个事务的。
51、在两阶段提交那部分,每当⼀个动作完成后,会有事件通知吗?⽐如在binlog写⼊成功后, 进⾏commit redo log,这个commit动作在成功或者失败后,会有回调或者事件通知吗?我感觉如果有通知机制的话,能更好的保持两个log的⼀致性,⽼师怎么认为呢?
答:这个就涉及“组提交”概念。是的,有通知,commit完成然后才继续后⾯的流程(⽐如返回
ack给客户端)。
52、redo log是为了快速响应SQL充当了粉板,这⾥有两个疑问:
答:你的理解是对的。
1.写redo log是顺序写,不⽤去“找位置”,⽽更新数据需要找位置。
2.其实是3次(redolog两次 binlog 1次)。不过在并发更新的时候会合并写。
53、请问⽤redolog恢复时还写binlog吗?反之呢?
答:崩溃恢复过程不写binlog了,⽤binlog恢复实例(或搭建备库)的时候,是会写redolog 的。
54、频繁的更新写⼊,导致redolog过⼤,适合短周期的备份? 答:Redolog固定⼤⼩,不会“导致过⼤”的。
55、binglog ⼀般建议设置啥模式,假如row模式binglog 怎么回复? 答:建议设置row模式,row模式⽇志⼀样的可以⽤于重放的。
56、既然write pos和checkout都是往后推移并循环的,⽽且当write pos赶上checkout的时候要停下来,将checkout往后推进,那么是不是意味着write pos的位置始终在checkout后⾯,最多在⼀起,⽽这和⽼师画的图有些出⼊,不知道我的理解是不是有些错误。
答:因为是“循环”的,图中这个状态下,write_pos 往前写,写到3号⽂件末尾,就回到0号继续写,这样你再理解看看“追”的状态。
说明⼀下,⽂中“write pos和checkpoint之间的是’粉板’上还空着的部分,可以⽤来记录新的操作。” 这句话,说的“空着的部分”,就是write pos 到3号⽂件末尾,再加上0号⽂件开头到
checkpoint 的部分。
57、innodb结构为内存池和后台线程 , 其中内存池⾥存在redo⽇志缓冲 和 缓冲池,其中缓冲池以⻚为单位缓冲磁盘数据 。
问 题 : 1.之前⽼师说更新语句时执⾏器调⽤innodb存储引擎先从内存读数据,指的就是从innodb缓存池中读取数据把,没有的话就去读取磁盘找, 找到后再同步到缓冲池。
2.在 server层中, 连接器先 查询缓存 , 这个缓存指的也是 innodb 的缓冲池么。mysql 通过公有的缓冲组件调⽤ innodb 的缓冲池来获取值。 获取不到在⾛ 分析器 --> 优化器 --> 执⾏器的流程 。
3.从缓冲中取的时候 ,为什么没有 分析器 --> 优化器 --> 执⾏器 的流程呢?
答:1. 是的。
2.不是,server 层的查询缓存就是(query_cache) Server层跟innodb的buffer pool是没有交集的,引擎没有暴露这个接⼝,只有操作数据的接⼝。
3.跟2类似,不是⼀个东⻄哦。
58、redo 是引擎提供的,binlog 是server ⾃带的,⽂中提到前者⽤在crash的恢复,后者⽤于库的恢复,两者是否在某种程度上是重复的?如果在都是追加写的情况下,是否两种⽇志都能⽤于 crash 与 库 的恢复呢?
答:Crash-safe是崩溃恢复,就是原地满⾎复活;binlog恢复是制造⼀个影分身(副本)出 来。
59、是否在redo没写时重启数据库,会使事务丢失?这个交易也失败。怎样情况重启会出现数据库数据不⼀致呢?oracle都存在重启后数据不⼀致的情况。数据不⼀致后怎么恢复?
答:Redolog没写,这个不算丢数据的。交易失败是预期的,也应该这样处理。就靠业务重试。
60、⽼师,我现在有点搞不懂 mysql 缓存机制和 innodb缓存机制的关系 ,以及 redo⽇志也有缓存,如果在缓存中还没同步到 redo ⽇志⾥的时候,mysql 发⽣的 crash 时,是否更新记录就真的没了?
答:会没了,但是没关系,因为redolog都没写完,表示你事务还没提交,中间出了错,本来就 应该没的。
61、⽼师 如果 binlog 或者 redo log 在写⼊磁盘的过程中故障了怎么保障数据⼀致? 答:整个事务回滚,数据也没有,⽇志也没有,也是⼀致的。
62、问题⼀:写redo⽇志也是写io(我理解也是外部存储)。同样耗费性能。怎么能做到优化呢?
问题⼆:数据库只有redo commit 之后才会真正提交到数据库吗?
答:1. Redolog是顺序写,并且可以组提交,还有别的⼀些优化,收益最⼤是是这两个因素;
2. 是这样, 正常执⾏是要commit 才算完, 但是崩溃恢复过程的话, 可以接受“redolog
prepare 并且binlog完整” 的情况。
63、两阶段提交那⾥不太懂,我理解是不是只要binlog保存成功,数据就能恢复,redolog 是不是就为了加快innodb引擎的写速度的?
答:Binlog写完就算,但是并不是⽤binlog恢复,恢复这个⼯作还是innodb做的。
64、redo log的机制看起来和ring buffer⼀样的;如果在重启后,需要通过检查binlog来确认redo log中处于prepare的事务是否需要commit,那是否不需要⼆阶段提交,直接以binlog的为准,如果binlog中不存在的,就认为是需要回滚的。这个地⽅,是不是我漏了什么,拉不通。 答:⽂章中有提到“binlog没有被⽤来做崩溃恢复”,历史上的原因是,这个是⼀开始就这么设计 的,所以不能只依赖binlog。操作上的原因是,binlog是可以关的,你如果有权限,可以set
sql_log_bin=0关掉本线程的binlog⽇志。 所以只依赖binlog来恢复就靠不住。
65、明⽩double write是为了保证数据⻚⾯的完整性,我上午问的是db 异常关闭起来需要做恢复的时候,因为MySQL 的redo 是物理逻辑⽇志,记录的是⻚⾯逻辑的改动,所以要保证数据
⻚⾯的完整性,这个就是靠double write 去保证的,是这样吗?⽽Oracle因为redo是物理⽇志,所以不需要double write技术的保证?
答:对,这样说就精确 。不过现在有些硬盘⽀持16K的原⼦写保证,就可以关掉double write
buffer,MariaDB 就提供了这个参数允许关掉。
66、多写场景需要吧 指标应该是RTO。有个问题既然innodb事务性这么强,为什么在恢复临时库不⽤redo恢复呢?直接对⻚进⾏恢复 数据⼀致性强,恢复时⻓也短,不⽤多写⼀份binlog, 减少写放⼤。这样做主从直接redo同步岂不是更好吗(就是redo量有点⼤) ?
答:Redo主要就是因为循环使⽤会覆盖;不过你说的这个逻辑,业界已经有团队通过改造
InnoDB⾏为在做了,只是不是官⽅做的,所以正⽂中没提。
67、binlog为什么说是逻辑⽇志呢?它⾥⾯有内容也会存储成物理⽂件,怎么说是逻辑⽽不是物理?
答:这样理解哈。 逻辑⽇志可以给别的数据库,别的引擎使⽤,已经⼤家都讲得通这个“逻辑”;
物理⽇志就只有“我”⾃⼰能⽤,别⼈没有共享我的“物理格式”。
68、MYSQL第⼆讲中提到binlog和redo log, 我感觉binlog很多余,按理是不是只要redo log就够了?
您讲的时候说redo log是InnoDB的要求,因为以plugin的形式加⼊到MySQL中,此时binlog作为Server层的⽇志已然存在,所以便有了两者共存的现状。但我觉得这并不能解释我们在只⽤
InonoDB引擎的时候还保留Binlog这种设计的原因。
答:binlog还不能去掉。⼀个原因是,redolog只有InnoDB有,别的引擎没有。另⼀个原因是,
redolog是循环写的,不持久保存,binlog的“归档”这个功能,redolog是不具备的。
69、Bin log ⽤于记录了完整的逻辑记录,所有的逻辑记录在 bin log ⾥都能找到,所以在备份恢复时,是以 bin log 为基础,通过其记录的完整逻辑操作,备份出⼀个和原库完整的数据。在两阶段提交时,若 redo log 写⼊成功,bin log 写⼊失败,则后续通过 bin log 恢复时,恢复的数据将会缺失⼀部分。(如 redo log 执⾏了 update t set status = 1,此时原库的数据 status 已更新为 1,⽽ bin log 写⼊失败,没有记录这⼀操作,后续备份恢复时,其 status = 0,导致数据不⼀致)。若先写⼊ bin log,当 bin log 写⼊成功,⽽ redo log 写⼊失败时,原库中的
status 仍然是 0 ,但是当通过 bin log 恢复时,其记录的操作是 set status = 1,也会导致数据不⼀致。其核⼼就是, redo log 记录的,即使异常重启,都会刷新到磁盘,⽽ bin log 记录的, 则主要⽤于备份。
我可以这样理解吗?还有就是如何保证 redo log 和 bin log 操作的⼀致性啊?
答:⼏乎全对,除了这个“两阶段提交时,若redo log写⼊成功,但binlog写⼊失败…”这句话。实际上,因为是两阶段提交,这时候redolog只是完成了prepare, ⽽binlog⼜失败,那么事务本身会回滚,所以这个库⾥⾯status的值是0。如果通过binlog 恢复出⼀个库,status值也是0。这样不算丢失,这样是合理的结果,两阶段就是保证⼀致性⽤的。你不⽤担⼼⽇志写错,那样就是
bug了。
70、问题⼀:redolog记录更新⽇志,当更新完⼀个表之后再进⾏查询,此时会将这个表的
redolog刷到物理表中再进⾏查询吗?如果不是的话是如何保证数据最新?
问题⼆:数据恢复是以binlog的记录为准吗?如果要考虑redolog,那redolog如何帮助恢复? 答:1. 不会。就直接从内存读⾛,内存是对的就⾏。
2. ⽤binlog是⽤在备份恢复到过程中,这个过程就是⽤全量备份+binlog,你可以认为没redolog 的帮助。
71、binlog感觉像oracle的归档⽇志,那么也有设置binlog⽇期的参数,这个参数是?默认值⼜是多少?
答:expire_logs_days。默认是0 表示不⾃动删除;⾮零的话,单位是天。
72、如果认可这个事务可以从crash恢复,起码要求服务器告知客户端事务成功了吧,那您说redo log prepare + bin log ok,就可以恢复了,说明bin log写⼊成功就算事务成功了?那最后
⼀步确实没什么⽤呀。
答:有⽤,如果redolog 已经commit了,崩溃恢复就不需要去找binlog。
73、请教下redo log 和 binlog 也是需要写⽂件的,也会消耗IO,这个不会影响数据库的性能吗? 从内容看redo log⾸先写道缓存中,如果这个时候断电了,缓存也清空了,尚未写道磁盘,这个时候不是redo log 不完整的如何保证恢复的完整性呢?
答:要写IO,是会影响,但是为了数据可靠性,还是要做的。Redolog是直接写盘的,更新的内存是数据的内存。如果没有写完就重启,就回滚,不算的丢数据。
74、pos和checkpoint的位置⼀開始是怎麼確定的呢?checkpoint什麼時候移動呢?應該怎麼移動?移動多少?
答:⼀开始就是从头了,中间如果有重启,也从重启前的位置继续。 移动就是向右,到末尾循环;移动多少 取决于事务要写下多少的⽇志。
75、怎么知道binlog是完整的?
答:⼀个事务的完整binlog是有固定格式,也就是说有固定结尾的。
76、两个控制⽇志写磁盘的性能参数 如果都设置1 会不会对io影响很⼤ 对⼤并发也要设成1 吗?
答:⼀般这两个都建议设置成1(有时候称双1),除⾮你的系统IO撑不住了要临时应急。
77、两阶段提交是针对⾃动提交事务的语句来说的吗?如果是⼿动提交事务呢?
执⾏更新语句,只更新当前session缓存。当⼿动commit的时候,才是 记录redo log 处于
prepare状态,执⾏器执⾏,记录binlog,然后 redlog commit。是这样吗?
如果⽤户⼿动commit,但是第三步redlog变成 commit的时候挂掉,这时候⽤户收到的执⾏结果是什么?—这时候恢复的时候是认可这次commit的。
答:不是,这个跟⼿动还是⾃动⽆关。你说的commit是⼀个命令,“提交这个事务”,包含了整个提交过程(也就是说两次redolog和⼀次binlog操作,都是在你的这个commit 命令中做的)。
78、关于提到的’数据⻚’这个词我没有太理解,是⼀种存储⽅式么?
答:MySQL的记录是以“⻚”为单位存取的,默认⼤⼩16K。也就是说,你要访问磁盘中⼀个记录,不会只读这个记录,⽽会把它所在的16K数据⼀起读⼊内存。
79、update后先写⼊内存,然后写redo log,那么写⼊的这条数据在内存中的驻留时间是怎么处理的?是redo log写⼊磁盘后从内存中删除吗?
答:不会删除,除⾮内存不够⽤。不过在数据从内存删除之前,系统会保证它会被更新到磁盘数据上。
80、我想模式redo_log成功,bin_log失败;或者反过来。该如何模拟呢?
答:这个稍微有点麻烦,最直接⽅法是GDB,停在两个函数中间,然后coredump出来。
81、如果更新写⼊redolog后处于prepare状态,此时系统突然断电,那么binlog没有写⼊记录,重启后数据库的实际数据根据redolog更新了,但与binlog的语句记录不符,那么binlog怎么办?
答:不会,这时候事务会回滚,binlog也没有,所以是⼀致的。
82、在⼀个⼤事物或⻓事物⾥,⼀边执⾏sql⼀边写redo log吗?未提交的事物也会写到redo log file吗?
答:会先写⼀块内存,叫做log_buffer⾥⾯,在提交的时候再⼀次性写到磁盘。
83、在binlog写⼊磁盘后,commit提交前发⽣crash,由于commit没有成功,那返回给客户端的消息是事物失败,但是在系统恢复的时候却会重新提交事物,使之成功,这不是在欺骗客户端嘛?问题很⼤啊。
答:不是,并没有返回“事务失败”呀,⽽是“执⾏异常”。执⾏异常本来就可能成功也可能失败 的。你想⼀下这个场景:执⾏全部完成了,在回复客户端的时候⽹络断了,这怎么算。
84 、redo log是prepare状态, 写binlog时crash; 以及binlog写成功, 但是redolog更新为
commit状态时crash;重启后的回复机制⼜是怎么做的呢? 答:第⼀个回滚,第⼆个事务有效。
85、定时备份也是通过执⾏当前时间到上⼀次备份时间之间的binlog来完成的吗? 答:这个其实也是⼀种做法,不会⼤家⽤的更多的还是直接找个备库再全量备⼀次。
86、有没有这样的命令dump⽇志得到查询历史SQL语句?
答:更新在binlog⾥⾯有记录,⽤mysqlbinlog⼯具可以,仅限更新语句。
87、有⼀段不太懂:具体来说,当有⼀条记录需要更新的时候,InnoDB 引擎就会先把记录写到redo log(粉板)⾥⾯,并更新内存,这个时候更新就算完成了。
这⾥所说的,并更新内存,值得是更新内存⾥⾯的数据吗? 即id为2的数据,
另⼀个问题,按照前⾯所讲的分区,那内存⾥⾯最⼤存储的数据量是否为4个G?(即,⽼板⼀直没时间写⼊账本,⼩⿊板记录的最⼤数据量)。
答:1. 对,更新内存
2. 粉板记录的最多的更新记录是4G。 我们说的内存是放数据的内存,就是buffer_pool的⼤
⼩。
88、问题⼀:我的数据表设计 id user ud,先做个多线程拿号登陆的功能,未避免拿到重复的号码,我百度到使⽤UPDATE $db SET ud=1, id=LAST_INSERT_ID(id) WHERE ud=0 LIMIT 1
;SELECT user FROM $db WHERE ROW_COUNT()>0 and id=LAST_INSERT_ID(); 这 两 句来取号,但是效率很低,数据⼀⼤,mysql还容易崩溃。请问有更好的⽅法吗?
问题⼆:我的第⼆个项⽬数据表设计 id user info。数据利润 1,user1,1001;1002;1003。我想查询包含1001的数据,⽤like的话,数据少的话还可以接受,当百万数据的时候,就会很卡很慢。想请教⽼师有其他的⽅案吗?
答:1. 你这个做法不好,应该先insert,拿到的这个last_insert_id就⾏
2. 如果有这种需求,最好不要把这些拆成单⾏。 或者创建另外⼀个表单独维护包含“1001”对应的集合。
89 、 redo ⽇ 志 在 prepare 阶 段 之 后 就 已 经 刷 盘 啦 ? 我 按 我 的 理 解 ,
innodb_flush_log_at_trx_commit 应该是控制在commit之后才会写磁盘啊?如果是没有问题, 如果不是,binlog刷盘后是⽆法保证redolog刷盘的。
答:这个prepare已经是在你执⾏“COMMIT”语句⾥⾯了。
90、innodb_flush_log_at_trx_commit这个参数设置成 1,是不是等于binlog的归档了呢?
答:不是,这个但是是控制redolog的。 binlog存起来就有“归档”的功能。
91、问题⼀:⽂中‘’update 语句执⾏流程‘’示意图,是先修改数据,在记⽇志。不应该是先写
⽇志(⽣成重做⽇志),在修改数据(缓存⾥)吗?
问题⼆:redo log两阶段提交具体是怎么实现呢?我理解就是直接记录哪个⻚⾯做了什么修改到
redolog(硬盘⽇志⽂件)就结束了,已经落盘了,prepare,和commit怎么理解呢?
答:1. 这两个其实是交叉发⽣的(对于⼀个有多次更新⽇志的事务来说),所以可以忽略先后。关键是他们都在“把⽇志写⼊redolog物理⽂件之前。
2. 有了binlog, 需要两阶段。
92、为什么binlog没有crash-safe的能⼒呢?不是写磁盘了吗?可以在重启后把宕机前的binlog 中记录下来的异常事务sql语句执⾏⼀遍?
答:⼀开始没这么设计,实际上现在的binlog也不够,奔溃恢复需要⽇志和引擎内存状态配合的。
93、mysql的redo log有没有log buffer?对于⾼并发事务或者批量事务 如何优化redo⽂件的写
⼊瓶颈?
答:有buffer的,事务整个完成才学到redolog⽂件,redolog是顺序写。
94 、checkpoint 是指redo buffer 落盘的位置, 还是指⽇志更新写到表中的位置( crash
recovery的起始点),我在理解oracle的checkpoint是后者的。。就不知道他们俩是否都⼀样? 答: Write pos是redo buffer接下来要写的位置, crash recovery 的起点就是checkpoint. (Crash recovery起点。
95、如果第三步⽤户不是想commit⽽是想rollback,但不巧在第三步的时候崩溃了,回复后根据redo log和binlog⼀致来⾃动commit?
答:如果⽤户执⾏rollback语句,整个事务就放弃了,不会进⼊“prepare”状态。
96、更新停留在redo-log bin-log上时,查询是如何把新数据也包括进来?是在查询启动的时候把redo-log的数据刷新到⻚数据⾥⾯么?同⼀个数据库⾥,查询和更新同样多时,岂不是会让redo-log的“粉笔板”效果失效?
答:不会,最新的结果会保存在内存⾥⾯,就是“掌柜的记忆”,查询直接从内存返回就可以了。
97、情形是这样的,我们因为磁盘IO异常导致数据库异常重启了,并发现某个表数据损坏了
(⽆数据备份)且mysql⽆法开启,⼀开始的做法innodb_force_recovery设置到1-6直到数据库可 以 启 动 , 然 后 进 ⾏ mysqldump 备 份 , 然 ⽽ 并 不 能 备 份 , 报 错 是mysqldump: Error 2013: Lost connection to MySQL server during query when dumping ta ble XX表
at row: 31961089。于是就跳过这个表进⾏备份,并修复了其他数据库,但是这个表的数据丢失最终请了外援修复好了,但是具体没告诉我们,不知道和我们这个有没联系?有没提示让我学学习下这⽅⾯?是可以⽤ibd⽂件修复吗?
答:你说的这个case我分析了⼀下。
1.这个现象应该是数据⻚( page) 的内容错了。 InnoDB 在读到数据⻚的时候会判断
checksum,碰到有不对的⻚,就会⾃⼰crash掉。
2.修改 force_recovery启动以后,mysqldump会显示Lost connection,表示出错的表是在主键索引上(如果是叶⼦节点,dump的时候是不会访问到的)。
3.这种场景的坏表修复,有⼀种⽅法,是把错误的page先忽略掉。每个page有checksum,可以扫⽂件找到checksum不对的page, 清空掉内容, 初始化成空的。( 另⼀种做法是修改
MySQL的代码让MySQL忽略这个错误,⽽不是crash)。
4.总之第3步的⽬的就是跳过那些已经错了的数据⻚,把表⾥⾯别的数据取出来。
5.按照前说的,可以判断出这个错误的⻚是在主键上⾯,所以会丢⼏⾏的。
6.找回这⼏⾏的⽅法,有⼏个地⽅: 这个表其他索引⾥⾯有部分字段;undolog;binlog;业务对账。 但是这些都不能保证能够100%拿回全部数据。
⼀般尽量⽤binlog,业务对账已经是属于数据库本身没辙了。
我碰到过这种情况,没有binlog的情况下,做到第5步,业务就满意了。最后总结⼀下 :⼀定要备份,包括数据和binlog。<