当前位置: 首页 > 科技观察

访谈八足随笔MySQL

时间:2023-03-19 01:27:14 科技观察

1.说说三大范式《第一范式》:数据库中的字段是“原子的”,不可分割,是单一职责的“第二范式”:“构建在基础上”第一范式”,第二范式要求数据库表中的每个实例或行必须“可以唯一区分”。为了实现区分,通常需要在表中增加一列来存储每个实例的唯一标识。这种独特的属性列被称为主键的“第三范式”:“基于第一和第二范式”,确保每一列都与主键列直接相关,而不是与非主键间接相关其他表中不存在的信息但是,在我们日常开发中,“并不是所有的表都必须满足三大范式”,有时候几个冗余的字段可以关联到更少的表,查询效率的提升可能是其次的定性改变。MyISAM和InnoDB有什么区别?“InnoDB支持事务,但MyISAM不支持”。“InnoDB支持外键,而MyISAM不支持”。《InnoDB是聚簇索引》,采用B+Tree作为索引结构,数据文件与索引绑定,必须有主键。“MyISAM是非聚集索引”,也是使用B+Tree作为索引结构。索引和数据文件是分开的,索引存放的是数据文件的指针。主键索引和二级索引是独立的。“InnoDB不保存表的具体行数”。“MyISAM使用一个变量来保存整个表的行数。”Innodb有"redolog"日志文件,MyISAM没有"Innodb存储文件有frm,ibd,而Myisam是frm,MYD,MYI"Innodb:frm是表定义文件,ibd是数据文件Myisam:frm是表定义file,myd是数据文件,myi是索引文件"InnoDB支持表锁和行锁,而MyISAM支持表级锁""InnoDB必须有唯一索引(主键)",如果不指定,InnoDB会生成一个隐藏的columnRow_id作为默认主键,“MyISAM可以不用”3.为什么推荐使用自增id作为主键?1、普通索引的B+树存储的是主键索引的值。如果值很大,会“导致普通索引的存储空间更大”2.使用自增id作为主键索引插入新数据只要放在页尾即可,直接“按顺序插入”,无需刻意维护。3.页面拆分易于维护。当插入数据的当前页快满时,就会发生Pagesplitting。如果主键索引不是自增id,那么可能会从页面中间插入数据,页面上的数据会频繁变化,“导致分页维护成本更高”。4.查询语句是如何执行的?1.通过connector与客户端“建立连接”2.通过“缓存查询”查看sql之前是否查询过,直接返回结果。如果没有,执行第三步3.通过分析器分析sql“是否正确”的语义,包括格式,表等4.通过优化器“优化语句”,比如选择索引,连接jointable的sequence5.“Verifypermission”,验证该表是否有查询权限,如果没有,则返回如果没有权限,则转第6步。通过执行器调用存储引擎执行SQL,然后返回“执行结果”5.在使用Innodb的情况下,update语句是如何执行的?以如下语句为例,c字段没有索引,id为主键索引updateTsetc=c+1whereid=2;1、executor首先寻找引擎获取id=2的行。id是主键,引擎直接使用树搜索找到这一行。如果id=2行所在的数据页已经“在内存中”,它会“不在内存中”“直接返回”给执行者,需要先“从磁盘读取”。"intomemory",然后"return"2.executor拿到引擎给的行数据,把这个值加1,比如原来是N,现在是N+1,得到一个新的行数据,然后调用引擎接口“写入这行新数据”3.引擎将这行新数据更新到内存中,同时“将这次更新操作记录到重做日志中”,并且重做日志此时处于“准备”状态。然后通知executor执行完成,可以随时提交事务4.executor“生成本次操作的binlog”,并“将binlog写入磁盘”5.executor调用“committransaction”接口引擎的,引擎写Changetheredologtocommitstatus,"updatecomplete"6.为什么Innodb事务需要分两个阶段提交?先写redolog再写binlog。假设当redolog写完,binlog还没有写完,MySQL进程异常重启。此时,该语句并没有记录在binlog中。然后你会发现,如果需要用这个binlog来恢复临时库,由于这个语句的“binlogloss”,所以临时库这次会更新的比较少,恢复的行中c的值为0,这与原库值不同。先写binlog,再写redolog。如果crash发生在binlog写入后,由于redolog还没有写入,crashrecovery后事务无效,所以这一行c的值为0。但是日志“changecfrom0to1”已经记录在binlog中。所以后面用binlog恢复的时候,“又出来一个事务”,恢复的行中c的值为1,和原来数据库的值不一样。可以看出,“如果不使用‘两阶段提交’,数据库的状态可能与从其日志中恢复的库的状态不一致”。7.什么是指数?相信大家小时候学汉字都会查字典。想一想您在字典中查找的步骤。我们通过a~z这个汉字的第一个字母一个一个地查找词典目录,最后找到这个词的页码。想一想,如果没有目录会怎么样,最坏的结果就是你翻到字典的最后一页才能找到你要找的词。索引“相当于我们字典里的目录”,可以大大提高我们在数据库中的查询效率。八。索引失效的场景有哪些?这里随便列几个,不同版本的mysql有不同的场景1.最左前缀规则(前导索引不能死,中间索引不能断2.不对索引做任何操作(计算,函数,自动/手动类型转换),否则索引失败转全表扫描3.索引中范围条件(between、<、>、in等)右侧的列不能继续使用,如as:selectfromuserwherec>5andb=4;4.当对索引字段使用(!=或<>)判断时,会导致索引失效,转为全表扫描5.当使用isnull/isnotnull对索引字段的判断,会导致索引失效,转全表扫描6.当索引字段使用like,以通配符('%string')开头时,会导致索引失效,转到全表扫描,也是最左前缀原则。7.索引字段是字符串,但不要加查询时使用单引号。会导致索引失效转全表扫描8.当索引字段使用or时,会导致索引失效转全表扫描9.为什么用B+树而不是B-tree?B+树只在叶子节点存储数据,叶子节点不存储具体数据,只存储key。查询更稳定,广度增加。而一个节点就是磁盘上的一个内存页,内存页的大小是固定的。与B-tree相比,B-tree可以存储更多的“Index节点”,宽度更大,树高更短,节点更小,一次拉取数据的磁盘IO次数更少,B+树只需要遍历叶子节点即可实现整棵树的遍历。而在数据库中,基于范围的查询非常频繁,效率更高。10.什么是WAL?有什么好处?WAL即Write-AheadLogging,意思是“所有的修改都先写入日志,再写入磁盘”。保证数据操作的原子性和持久性。好处:1.“读写完全可以并发执行”,不会互相阻塞。2、先写入日志,磁盘写入由“随机写入变为顺序写入”。它减少了客户端的延迟。而且,由于顺序写入的概率很大,在一个磁盘块内,这样产生的IO次数也大大减少。3、写入日志当数据库崩溃时,“可以使用日志恢复磁盘数据”11、什么是返回表?回表就是先通过数据库索引扫描出索引树中数据的行,得到主键id,然后通过主键id得到主键索引号中的数据,即基于非主键索引的查询需要多扫描一棵索引树。12、什么是指数下推?如果索引列有一些判断条件,MySQL会将这部分判断条件传递给存储引擎,然后存储引擎判断索引是否满足MySQL服务器传递的条件。“只有当索引满足条件时,才会检索数据返回给MySQL服务器。”十三。什么是覆盖索引?覆盖索引是指查询语句的执行只需要从索引中获取,不需要从数据表中读取,可以减少返回表的次数。例如:selectidfromtwhereage=1;id是主键索引,age是普通索引,age索引树存储的是渐变信息,可以直接返回14。什么是最左前缀原则?最左边的前缀其实是指where条件中出现的字段“如果组合索引中只有部分列,则这部分列的触发索引顺序”是按照索引时的顺序从前到后触发的被定义为。最左边的列不能触发,后面的所有列索引Neither都不能触发。比如“有一个组合索引(a,b,c)”wherea=1andb=1,a,b会命中组合索引wherea=1andc=1,那么a会命中组合索引,c不会命中whereb=1andc=1此时不会命中复合索引。15、普通索引和唯一索引如何选择?Query当普通索引为条件时,会扫描查询数据,直到扫描全表。当唯一索引为查询条件时,查询的数据会直接返回,不会继续扫描表更新普通索引,而是直接更新操作到changebuffer,然后结束唯一索引到判断数据是否冲突。因此,“唯一索引更适合查询场景,普通索引更适合插入。场景16.什么是事务?它有什么特点?事务指的是程序中必须进行的一系列操作成功完成。如果一个失败,所有这些都将失败。特点“1。原子性”:要么都执行成功,要么都不执行。”2.“一致性”:交易前后数据的完整性必须一致。“3.隔离”:隔离是指同事触发多个事务时,不能被其他事务的操作所干扰,多个并发事务之间必须相互隔离。“4.持久性(Durability)”:交易完成后的变化是永久性的。17.交易的隔离级别?1、“ReadCommitted”:即“读取已提交的数据”2、“ReadUncommitted”:即可以“读取未提交的数据”3、“Repeatableread”:可重复读是指一个事务内,开始时读取的数据与事务结束前“随时读取同一批数据”是一致的4、“可序列化”:最高的事务隔离级别,无论多少事务,都是“按顺序一个一个执行”的“脏读”脏读是指“从其他事务中读取未提交的数据”,未提交的意思是这些数据可能会被回滚,也就是可能没有存储在数据库中端,也就是不存在的数据,已经读过且最终一定存在的数据就是脏读“不可重复读”,相对于可重复读,不可重复读指的是“同一批次的数据读取在不同的时间可能是不同的”在同一个交易中。。“幻读”Phantomreading用于数据插入(INSERT)操作。假设事务A更改了一些行的内容,但是还没有提交,此时事务B插入与事务A更改前的记录相同的记录行,并在事务A提交之前提交,此时,在事务A中查询,会发现“貌似刚才的改动对某些数据没有影响”,但实际上只是事务B插入的,这就叫幻读。18.binlog有什么作用?Binlog是归档日志。属于Server层的日志是二进制格式的文件,用于“记录用户更新到数据库的SQL语句信息”。主要功能是主从复制数据恢复19、undolog有什么作用?Undolog是InnoDB存储引擎的日志,用于保证数据的原子性。数据为修改前的数据,可用于回滚,也可提供多版本并发控制(MVCC)下的读取。主要功能是事务回滚实现多版本控制(MVCC)20.relaylog是做什么的?relaylog是中继日志,“在主从同步时使用”,它是一个中间的临时日志文件,用于存储从主节点同步过来的binlog日志内容。master主节点的binlog传输到slave节点后,写入relaylog,slave节点的slavesql线程从relaylog中读取日志,应用到slave节点本地。从服务器I/O线程读取主服务器的二进制日志记录到从服务器的本地文件中,然后SQL线程读取relay-log日志的内容应用到从服务器上,所以“从服务器和主服务器的数据是一致的”。21、redolog有什么作用?Redolog是“InnoDB存储引擎特有的一种日志”。它用于记录事务操作的变化。它记录数据修改后的值,不管事务是否提交。它可以做“数据恢复和提供崩溃安全能力”。当有增删改查相关的操作时,会先记录到Innodb中,然后修改缓存页中的数据。数据写入磁盘”。22、redolog是如何记录日志的?InnoDB的redolog是有固定大小的。比如可以配置为4个文件一组,每个文件的大小为1GB,所以一个一共可以记录4GB的操作,“从头写,然后回到头,最后循环写”,所以,如果数据满了,还没来得及真正刷数据到disk,那么就会出现“内存抖动”的现象,从肉眼的角度,会发现mysql会down一段时间,此时正在刷新磁盘。up。23.什么是redolog和binlog的区别?1、“redolog”是“Innodb”独有的日志,而“binlog”是在“server”层,使用所有的存储引擎。2、“redolog”记录了“具体值”,对某个页面做了什么修改,“binlog”中记录了“操作内容”3.“binlog”达到上限或flushlog“会生成一个新文件”,“redolog”有固定大小“只能回收”4.“binlog日志不具备防撞能力”,只能用于归档。并且重做日志具有崩溃安全能力。24.我们来谈谈mvcc。有什么作用?MVCC:多版本并发控制是现代数据库(包括MySQL、Oracle、PostgreSQL等)引擎实现中处理读写冲突的常用手段。目的是“提高数据库在高并发场景下的Throughput性能”。在MVCC协议下,每个读操作都会看到一个一致的快照,“这个快照是基于整个库的”,可以实现非阻塞读,用来“支持读提交和可重复读隔离级别的实现”。MVCC允许数据有多个版本。此版本可以是时间戳或全局递增的事务ID。在同一时间点,不同的交易看到不同的数据。此修改后的数据“记录在undolog中”。的。25、一条Sql语句的查询总是慢的原因是什么?“1.没有使用索引”,比如函数导致的索引失效,或者本身没有索引。《3.优化器选择了错误的索引》《考虑使用》forceindex强制索引走26.一条Sql语句查询偶尔慢是什么原因?“1.数据库正在刷新脏页”比如“redolog满了”,“内存不够”释放内存,如果是脏页,需要刷新,mysql在正常空闲时刷新脏页state”“2.没有拿到锁”二十七。Mysql主从如何同步数据?1.master主库将本次更新的事件类型写入主库的binlog文件2.master“创建日志转储线程通知slave”需要更新数据3.“slave”发送一个向master节点请求,“写入binlog文件内容到本地relaylog”4.“slave打开sql线程”读取relaylog中的内容,“在本地重新执行内容”,完成主从数据同步“同步策略”:1、“全同步复制”:主库强制同步日志到从库,所有从库执行完毕后返回给客户端。性能很差。2、“半同步复制”:主库至少收到从库的一次确认后,才认为操作成功。28、如何解决主从延迟?1、MySQL5.6版本以后,通过将SQL线程转换成多个工作线程,提供了一种“并行复制”的方法。Replay2.“提升机器配置”(御道)3.在业务初期选择合适的分库分表策略,“避免单表数据库过大”带来额外的复制压力4.“避免长事务””5。《避免数据库进行各种大型计算》6、对于一些对延迟敏感的业务,“直接使用主库读取”29、删除表数据后,表的大小没有变化。为什么?当使用delete删除数据时,其实对应的数据行并不是真正的删除,而是“逻辑删除”。InnoDB只是“将其标记为可重用状态”,所以表空间不会变小。为什么不推荐使用VarChar?超过255?当定义varchar的长度小于等于255时,长度标识位需要一个字节(utf-8编码)。当大于255时,长度标识位需要两个字节,创建的“索引也会失效”301、如何实现分布式事务?1.“本地消息表”2.“消息事务”3.“两阶段提交”4.“三阶段提交”5.《TCC》6.《BestEffortNotification》7.《SeataFramework》七大分布式事务解决方案,一次告诉你32.Mysql中有哪些锁?下面不完整,主要是了解锁的含义,可以根据锁的属性分类:共享锁,独占锁。基于锁的粒度分类:表锁、行锁、记录锁、间隙锁、邻键锁。死锁33.为什么不使用长事务?1、并发情况下,数据库“连接池容易爆”2、“容易造成大量阻塞和锁超时”。长事务也占用锁资源,还可能拖累整个库,3.执行时间长,容易造成“主从延迟”4.“回滚需要的时间比较长”。交易越长,整个时间段内的交易越多。5、“undolog日志越来越大”长事务意味着系统中会有很旧的事务视图。由于这些事务可能随时访问数据库中的任何数据,因此在事务提交之前,必须保留其在数据库中可能使用的回滚记录,这将导致占用大量的存储空间。三十四。缓冲池有什么作用?缓冲池是一个内存区域。为了“提高数据库的性能”,数据库在操作数据时,将硬盘上的数据加载到缓冲池中,而不是直接与硬盘打交道。缓冲池中的数据就是缓冲池中的数据。数据库的增删改查都是在缓冲池上进行的。缓冲池中缓存的数据内容也是一个数据页。其中“双向链表一共有三个”:“空闲链表”用来帮助我们找到空闲的缓存页“刷新链表”用来查找脏缓存页,也就是需要刷新的缓存页.“lru链表”用于淘汰不常访问的缓存页。分为热数据区和冷数据区。冷数据区主要存放不经常使用的数据预读机制:BufferPool有一个特殊的特性叫做预读。当存储引擎的接口被服务器层调用时,会在响应的同时进行预判断,使用下次可能用到的数据。加载数据和索引到BufferPool35.说说你的Sql调优思路1.《表结构优化》1.1拆分字段1.2字段类型选择1.3字段类型大小限制1.4合理增加冗余字段1.5新字段必须有默认值2.《索引》2.1索引字段的选择2.2善用mysql支持的索引下推,涵盖索引等功能2.3唯一索引和普通索引的选择3.《查询语句》3.1避免索引失效3.2where条件字段的合理写法order3.3小表驱动大表3.4可以使用forceindex()来防止优化器选择错误的索引4.“分库分表”