游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

面渣逆袭MySQL六十六问,两万字五十图详解!有点六

  不知不觉,面渣逆袭系列已经肝了差不多十篇,每一篇都是上万字,几十图,基本上涵盖了面试的主要知识点,这期MySQL结束之后,这个系列可能会暂时告一段落,作为面渣逆袭系列第一阶段的收官之作,大家多多点赞、收藏哦!
  基础
  MySQLogo
  作为SQLBoy,基础部分不会有人不会吧?面试也不怎么问,基础掌握不错的小伙伴可以跳过这一部分。当然,可能会现场写一些SQL语句,SQ语句可以通过牛客、LeetCode、LintCode之类的网站来练习。1。什么是内连接、外连接、交叉连接、笛卡尔积呢?内连接(innerjoin):取得两张表中满足存在连接匹配关系的记录。外连接(outerjoin):不只取得两张表中满足存在连接匹配关系的记录,还包括某张表(或两张表)中不满足匹配关系的记录。交叉连接(crossjoin):显示两张表所有记录一一对应,没有匹配关系进行筛选,它是笛卡尔积在SQL中的实现,如果A表有m行,B表有n行,那么A和B交叉连接的结果就有mn行。笛卡尔积:是数学中的一个概念,例如集合A{a,b},集合B{1,2,3},那么AB{,,,b,0,b,1,b,2,}。2。那MySQL的内连接、左连接、右连接有有什么区别?
  MySQL的连接主要分为内连接和外连接,外连接常用的有左连接、右连接。
  MySQLjoins来源菜鸟教程innerjoin内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集leftjoin在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。rightjoin在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。3。说一下数据库的三大范式?
  数据库三范式第一范式:数据表中的每一列(每个字段)都不可以再拆分。例如用户表,用户地址还可以拆分成国家、省份、市,这样才是符合第一范式的。第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。例如订单表里,存储了商品信息(商品价格、商品类型),那就需要把商品ID和订单ID作为联合主键,才满足第二范式。第三范式:在满足第二范式的基础上,表中的非主键只依赖于主键,而不依赖于其他非主键。例如订单表,就不能存储用户信息(姓名、地址)。
  你设计遵守范式吗?
  三大范式的作用是为了控制数据库的冗余,是对空间的节省,实际上,一般互联网公司的设计都是反范式的,通过冗余一些数据,避免跨表跨库,利用空间换时间,提高性能。4。varchar与char的区别?
  varchar
  char:char表示定长字符串,长度是固定的;如果插入数据的长度小于char的固定长度时,则用空格填充;因为长度固定,所以存取速度要比varchar快很多,甚至能快50,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法;对于char来说,最多能存放的字符个数为255,和编码无关
  varchar:varchar表示可变长字符串,长度是可变的;插入的数据是多长,就按照多长来存储;varchar在存取方面与char相反,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是时间换空间的做法;对于varchar来说,最多能存放的字符个数为65532
  日常的设计,对于长度相对固定的字符串,可以使用char,对于长度不确定的,使用varchar更合适一些。5。blob和text有什么区别?blob用于存储二进制数据,而text用于存储大字符串。blob没有字符集,text有一个字符集,并且根据字符集的校对规则对值进行排序和比较6。DATETIME和TIMESTAMP的异同?
  相同点:两个数据类型存储时间的表现格式一致。均为YYYYMMDDHH:MM:SS两个数据类型都包含日期和时间部分。两个数据类型都可以存储微秒的小数秒(秒后6位小数秒)
  区别:
  DATETIME和TIMESTAMP的区别日期范围:DATETIME的日期范围是1000010100:00:00。000000到9999123123:59:59。999999;TIMESTAMP的时间范围是1970010100:00:01。000000UTC到2038010903:14:07。999999UTC存储空间:DATETIME的存储空间为8字节;TIMESTAMP的存储空间为4字节时区相关:DATETIME存储时间与时区无关;TIMESTAMP存储时间与时区有关,显示的值也依赖于时区默认值:DATETIME的默认值为null;TIMESTAMP的字段默认不为空(notnull),默认值为当前时间(CURRENTTIMESTAMP)7。MySQL中in和exists的区别?
  MySQL中的in语句是把外表和内表作hash连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。我们可能认为exists比in语句的效率要高,这种说法其实是不准确的,要区分情景:如果查询的两个表大小相当,那么用in和exists差别不大。如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。notin和notexists:如果查询语句使用了notin,那么内外表都进行全表扫描,没有用到索引;而notextsts的子查询依然能用到表上的索引。所以无论那个表大,用notexists都比notin要快。8。MySQL里记录货币用什么字段类型比较好?
  货币在数据库中MySQL常用Decimal和Numric类型表示,这两种类型被MySQL实现为同样的类型。他们被用于保存与货币有关的数据。
  例如salaryDECIMAL(9,2),9(precision)代表将被用于存储值的总的小数位数,而2(scale)代表将被用于存储小数点后的位数。存储在salary列中的值的范围是从9999999。99到9999999。99。
  DECIMAL和NUMERIC值作为字符串存储,而不是作为二进制浮点数,以便保存那些值的小数精度。
  之所以不使用float或者double的原因:因为float和double是以二进制存储的,所以有一定的误差。9。MySQL怎么存储emoji?
  MySQL可以直接使用字符串存储emoji。
  但是需要注意的,utf8编码是不行的,MySQL中的utf8是阉割版的utf8,它最多只用3个字节存储字符,所以存储不了表情。那该怎么办?
  需要使用utf8mb4编码。altertableblogsmodifycontenttextCHARACTERSETutf8mb4COLLATEutf8mb4unicodecinotnull;10。drop、delete与truncate的区别?
  三者都表示删除,但是三者有一些差别:
  deletetruncatedrop类型属于DML属于DDL属于DDL回滚可回滚不可回滚不可回滚删除内容表结构还在,删除表的全部或者一部分数据行表结构还在,删除表中的所有数据从数据库中删除表,所有数据行,索引和权限也会被删除删除速度删除速度慢,需要逐行删除删除速度快删除速度最快
  因此,在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate。11。UNION与UNIONALL的区别?如果使用UNIONALL,不会合并重复的记录行效率UNION高于UNIONALL12。count(1)、count()与count(列名)的区别?
  三种计数方式
  执行效果:count()包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULLcount(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULLcount(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。
  执行速度:列名为主键,count(列名)会比count(1)快列名不为主键,count(1)会比count(列名)快如果表多个列并且没有主键,则count(1)的执行效率优于count()如果有主键,则selectcount(主键)的执行效率是最优的如果表只有一个字段,则selectcount()最优。13。一条SQL查询语句的执行顺序?
  查询语句执行顺序FROM:对FROM子句中的左表和右表执行笛卡儿积(Cartesianproduct),产生虚拟表VT1liON:对虚拟表VT1应用ON筛选,只有那些符合的行才被插入虚拟表VT2中JOIN:如果指定了OUTERJOIN(如LEFTOUTERJOIN、RIGHTOUTERJOIN),那么保留表中未匹配的行作为外部行添加到虚拟表VT2中,产生虚拟表VT3。如果FROM子句包含两个以上表,则对上一个连接生成的结果表VT3和下一个表重复执行步骤1)步骤3),直到处理完所有的表为止WHERE:对虚拟表VT3应用WHERE过滤条件,只有符合的记录才被插入虚拟表VT4中GROUPBY:根据GROUPBY子句中的列,对VT4中的记录进行分组操作,产生VT5CUBEROLLUP:对表VT5进行CUBE或ROLLUP操作,产生表VT6HAVING:对虚拟表VT6应用HAVING过滤器,只有符合的记录才被插入虚拟表VT7中。SELECT:第二次执行SELECT操作,选择指定的列,插入到虚拟表VT8中DISTINCT:去除重复数据,产生虚拟表VT9ORDERBY:将虚拟表VT9中的记录按照进行排序操作,产生虚拟表VT10。11)LIMIT:取出指定行的记录,产生虚拟表VT11,并返回给查询用户ol数据库架构14。说说MySQL的基础架构?
  在这里插入图片描述
  MySQL逻辑架构图主要分三层:客户端:最上层的服务并不是MySQL所独有的,大多数基于网络的客户端服务器的工具或者服务都有类似的架构。比如连接处理、授权认证、安全等等。Server层:大多数MySQL的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(例如,日期、时间、数学和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。存储引擎层:第三层包含了存储引擎。存储引擎负责MySQL中数据的存储和提取。Server层通过API与存储引擎进行通信。这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明。15。一条SQL查询语句在MySQL中如何执行的?先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限会先查询缓存(MySQL8。0版本以前)。如果没有缓存,分析器进行语法分析,提取sql语句中select等关键元素,然后判断sql语句是否有语法错误,比如关键词是否正确等等。语法解析之后,MySQL的服务器会对查询的语句进行优化,确定执行的方案。完成查询优化后,按照生成的执行计划调用数据库引擎接口,返回执行结果。存储引擎16。MySQL有哪些常见存储引擎?
  主要存储引擎
  主要存储引擎以及功能如下:
  功能MylSAMMEMORYInnoDB存储限制256TBRAM64TB支持事务NoNoYes支持全文索引YesNoYes支持树索引YesYesYes支持哈希索引NoYesYes支持数据缓存NoNAYes支持外键NoNoYes
  MySQL5。5之前,默认存储引擎是MylSAM,5。5之后变成了InnoDB。
  InnoDB支持的哈希索引是自适应的,InnoDB会根据表的使用情况自动为表生成哈希索引,不能人为干预是否在一张表中生成哈希索引。
  MySQL5。6开始InnoDB支持全文索引。17。那存储引擎应该怎么选择?
  大致上可以这么选择:大多数情况下,使用默认的InnoDB就够了。如果要提供提交、回滚和恢复的事务安全(ACID兼容)能力,并要求实现并发控制,InnoDB就是比较靠前的选择了。如果数据表主要用来插入和查询记录,则MyISAM引擎提供较高的处理效率。如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存的MEMORY引擎中,MySQL中使用该引擎作为临时表,存放查询的中间结果。
  使用哪一种引擎可以根据需要灵活选择,因为存储引擎是基于表的,所以一个数据库中多个表可以使用不同的引擎以满足各种性能和实际需求。使用合适的存储引擎将会提高整个数据库的性能。18。InnoDB和MylSAM主要有什么区别?
  PS:MySQL8。0都开始慢慢流行了,如果不是面试,MylSAM其实可以不用怎么了解。
  InnoDB和MylSAM主要有什么区别
  1。存储结构:每个MyISAM在磁盘上存储成三个文件;InnoDB所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。
  2。事务支持:MyISAM不提供事务支持;InnoDB提供事务支持事务,具有事务(commit)、回滚(rollback)和崩溃修复能力(crashrecoverycapabilities)的事务安全特性。
  3最小锁粒度:MyISAM只支持表级锁,更新时会锁住整张表,导致其它查询和更新都会被阻塞InnoDB支持行级锁。
  4。索引类型:MyISAM的索引为聚簇索引,数据结构是B树;InnoDB的索引是非聚簇索引,数据结构是B树。
  5。主键必需:MyISAM允许没有任何索引和主键的表存在;InnoDB如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。
  6。表的具体行数:MyISAM保存了表的总行数,如果selectcount()fromtable;会直接取出出该值;InnoDB没有保存表的总行数,如果使用selectcount()fromtable;就会遍历整个表;但是在加了wehre条件后,MyISAM和InnoDB处理的方式都一样。
  7。外键支持:MyISAM不支持外键;InnoDB支持外键。日志19。MySQL日志文件有哪些?分别介绍下作用?
  MySQL主要日志
  MySQL日志文件有很多,包括:错误日志(errorlog):错误日志文件对MySQL的启动、运行、关闭过程进行了记录,能帮助定位MySQL问题。慢查询日志(slowquerylog):慢查询日志是用来记录执行时间超过longquerytime这个变量定义的时长的查询语句。通过慢查询日志,可以查找出哪些查询语句的执行效率很低,以便进行优化。一般查询日志(generallog):一般查询日志记录了所有对MySQL数据库请求的信息,无论请求是否正确执行。二进制日志(binlog):关于二进制日志,它记录了数据库所有执行的DDL和DML语句(除了数据查询语句select、show等),以事件形式记录并保存在二进制文件中。
  还有两个InnoDB存储引擎特有的日志文件:重做日志(redolog):重做日志至关重要,因为它们记录了对于InnoDB存储引擎的事务日志。回滚日志(undolog):回滚日志同样也是InnoDB引擎提供的日志,顾名思义,回滚日志的作用就是对数据进行回滚。当事务对数据库进行修改,InnoDB引擎不仅会记录redolog,还会生成对应的undolog日志;如果事务执行失败或调用了rollback,导致事务需要回滚,就可以利用undolog中的信息将数据回滚到修改之前的样子。20。binlog和redolog有什么区别?binlog会记录所有与数据库有关的日志记录,包括InnoDB、MyISAM等存储引擎的日志,而redolog只记InnoDB存储引擎的日志。记录的内容不同,binlog记录的是关于一个事务的具体操作内容,即该日志是逻辑日志。而redolog记录的是关于每个页(Page)的更改的物理情况。写入的时间不同,binlog仅在事务提交前进行提交,也就是只写磁盘一次。而在事务进行的过程中,却不断有redoertry被写入redolog中。写入的方式也不相同,redolog是循环写入和擦除,binlog是追加写入,不会覆盖已经写的文件。21。一条更新语句怎么执行的了解吗?
  更新语句的执行是Server层和引擎层配合完成,数据除了要写入表中,还要记录相应的日志。
  update执行执行器先找引擎获取ID2这一行。ID是主键,存储引擎检索数据,找到这一行。如果ID2这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。执行器拿到引擎给的行数据,把这个值加上1,比如原来是N,现在就是N1,得到新的一行数据,再调用引擎接口写入这行新数据。引擎将这行新数据更新到内存中,同时将这个更新操作记录到redolog里面,此时redolog处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。执行器生成这个操作的binlog,并把binlog写入磁盘。执行器调用引擎的提交事务接口,引擎把刚刚写入的redolog改成提交(commit)状态,更新完成。
  从上图可以看出,MySQL在执行更新语句的时候,在服务层进行语句的解析和执行,在引擎层进行数据的提取和存储;同时在服务层对binlog进行写入,在InnoDB内进行redolog的写入。
  不仅如此,在对redolog写入时有两个阶段的提交,一是binlog写入之前prepare状态的写入,二是binlog写入之后commit状态的写入。22。那为什么要两阶段提交呢?
  为什么要两阶段提交呢?直接提交不行吗?
  我们可以假设不采用两阶段提交的方式,而是采用单阶段进行提交,即要么先写入redolog,后写入binlog;要么先写入binlog,后写入redolog。这两种方式的提交都会导致原先数据库的状态和被恢复后的数据库的状态不一致。
  先写入redolog,后写入binlog:
  在写完redolog之后,数据此时具有crashsafe能力,因此系统崩溃,数据会恢复成事务开始之前的状态。但是,若在redolog写完时候,binlog写入之前,系统发生了宕机。此时binlog没有对上面的更新语句进行保存,导致当使用binlog进行数据库的备份或者恢复时,就少了上述的更新语句。从而使得id2这一行的数据没有被更新。
  先写redolog,后写binlog的问题
  先写入binlog,后写入redolog:
  写完binlog之后,所有的语句都被保存,所以通过binlog复制或恢复出来的数据库中id2这一行的数据会被更新为a1。但是如果在redolog写入之前,系统崩溃,那么redolog中记录的这个事务会无效,导致实际数据库中id2这一行的数据并没有更新。
  先写binlog,后写redolog的问题
  简单说,redolog和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。23。redolog怎么刷入磁盘的知道吗?
  redolog的写入不是直接落到磁盘,而是在内存中设置了一片称之为redologbuffer的连续内存空间,也就是redo日志缓冲区。
  redolog缓冲
  什么时候会刷入磁盘?
  在如下的一些情况中,logbuffer的数据会刷入磁盘:logbuffer空间不足时
  logbuffer的大小是有限的,如果不停的往这个有限大小的logbuffer里塞入日志,很快它就会被填满。如果当前写入logbuffer的redo日志量已经占满了logbuffer总容量的大约一半左右,就需要把这些日志刷新到磁盘上。事务提交时
  在事务提交时,为了保证持久性,会把logbuffer中的日志全部刷到磁盘。注意,这时候,除了本事务的,可能还会刷入其它事务的日志。后台线程输入
  有一个后台线程,大约每秒都会刷新一次logbuffer中的redolog到磁盘。正常关闭服务器时触发checkpoint规则
  重做日志缓存、重做日志文件都是以块(block)的方式进行保存的,称之为重做日志块(redologblock),块的大小是固定的512字节。我们的redolog它是固定大小的,可以看作是一个逻辑上的loggroup,由一定数量的logblock组成。
  redolog分块和写入
  它的写入方式是从头到尾开始写,写到末尾又回到开头循环写。
  其中有两个标记位置:
  writepos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到磁盘。
  writepos和checkpoint
  当writepos追上checkpoint时,表示redolog日志已经写满。这时候就不能接着往里写数据了,需要执行checkpoint规则腾出可写空间。
  所谓的checkpoint规则,就是checkpoint触发后,将buffer中日志页都刷到磁盘。SQL优化24。慢SQL如何定位呢?
  慢SQL的监控主要通过两个途径:
  发现慢SQL慢查询日志:开启MySQL的慢查询日志,再通过一些工具比如mysqldumpslow去分析对应的慢查询日志,当然现在一般的云厂商都提供了可视化的平台。服务监控:可以在业务的基建中加入对慢SQL的监控,常见的方案有字节码插桩、连接池扩展、ORM框架过程,对服务运行中的慢SQL进行监控和告警。25。有哪些方式优化慢SQL?
  慢SQL的优化,主要从两个方面考虑,SQL语句本身的优化,以及数据库设计的优化。
  SQL优化避免不必要的列
  这个是老生常谈,但还是经常会出的情况,SQL查询的时候,应该只查询需要的列,而不要包含额外的列,像slect这种写法应该尽量避免。分页优化
  在数据量比较大,分页比较深的情况下,需要考虑分页的优化。
  例如:selectfromtablewheretype2andlevel9orderbyidasclimit190289,10;
  优化方案:延迟关联先通过where条件提取出主键,在将该表与原数据表关联,通过主键id提取数据行,而不是通过原来的二级索引提取数据行例如:selecta。fromtablea,
  (selectidfromtablewheretype2andlevel9orderbyidasclimit190289,10)b
  wherea。idb。id书签方式书签方式就是找到limit第一个参数对应的主键值,根据这个主键值再去过滤并limit例如:selectfromtablewhereid(selectfromtablewheretype2andlevel9orderbyidasclimit190索引优化
  合理地设计和使用索引,是优化慢SQL的利器。
  利用覆盖索引
  InnoDB使用非主键索引查询数据时会回表,但是如果索引的叶节点中已经包含要查询的字段,那它没有必要再回表查询了,这就叫覆盖索引
  例如对于如下查询:selectnamefromtestwherecity上海
  我们将被查询的字段建立到联合索引中,这样查询结果就可以直接从索引中获取altertabletestaddindexidxcityname(city,name);
  低版本避免使用or查询
  在MySQL5。0之前的版本要尽量避免使用or查询,可以使用union或者子查询来替代,因为早期的MySQL版本使用or查询可能会导致索引失效,高版本引入了索引合并,解决了这个问题。
  避免使用!或者操作符
  SQL中,不等于操作符会导致查询引擎放弃查询索引,引起全表扫描,即使比较的字段上有索引
  解决方法:通过把不等于操作符改成or,可以使用索引,避免全表扫描
  例如,把column’aaa’,改成column’aaa’orcolumn’aaa’,就可以使用索引了
  适当使用前缀索引
  适当地使用前缀所云,可以降低索引的空间占用,提高索引的查询效率。
  比如,邮箱的后缀都是固定的xxx。com,那么类似这种后面几位为固定值的字段就非常适合定义为前缀索引altertabletestaddindexindex2(email(6));
  PS:需要注意的是,前缀索引也存在缺点,MySQL无法利用前缀索引做orderby和groupby操作,也无法作为覆盖索引
  避免列上函数运算
  要避免在列字段上进行算术运算或其他表达式运算,否则可能会导致存储引擎无法正确使用索引,从而影响了查询的效率selectfromtestwhereid150;selectfromtestwheremonth(updateTime)7;
  正确使用联合索引
  使用联合索引的时候,注意最左匹配原则。JOIN优化
  优化子查询
  尽量使用Join语句来替代子查询,因为子查询是嵌套查询,而嵌套查询会新创建一张临时表,而临时表的创建与销毁会占用一定的系统资源以及花费一定的时间,同时对于返回结果集比较大的子查询,其对查询性能的影响更大
  小表驱动大表
  关联查询的时候要拿小表去驱动大表,因为关联的时候,MySQL内部会遍历驱动表,再去连接被驱动表。
  比如leftjoin,左表就是驱动表,A表小于B表,建立连接的次数就少,查询速度就被加快了。selectnamefromAleftjoinB;
  适当增加冗余字段
  增加冗余字段可以减少大量的连表查询,因为多张表的连表查询性能很低,所有可以适当的增加冗余字段,以减少多张表的关联查询,这是以空间换时间的优化策略
  避免使用JOIN关联太多的表
  《阿里巴巴Java开发手册》规定不要join超过三张表,第一join太多降低查询的速度,第二join的buffer会占用更多的内存。
  如果不可避免要join多张表,可以考虑使用数据异构的方式异构到ES中查询。排序优化
  利用索引扫描做排序
  MySQL有两种方式生成有序结果:其一是对结果集进行排序的操作,其二是按照索引顺序扫描得出的结果自然是有序的
  但是如果索引不能覆盖查询所需列,就不得不每扫描一条记录回表查询一次,这个读操作是随机IO,通常会比顺序全表扫描还慢
  因此,在设计索引时,尽可能使用同一个索引既满足排序又用于查找行
  例如:建立索引(date,staffid,customerid)selectstaffid,customeridfromtestwheredate20100101orderbystaffid,customerid;
  只有当索引的列顺序和ORDERBY子句的顺序完全一致,并且所有列的排序方向都一样时,才能够使用索引来对结果做排序UNION优化
  条件下推
  MySQL处理union的策略是先创建临时表,然后将各个查询结果填充到临时表中最后再来做查询,很多优化策略在union查询中都会失效,因为它无法利用索引
  最好手工将where、limit等子句下推到union的各个子查询中,以便优化器可以充分利用这些条件进行优化
  此外,除非确实需要服务器去重,一定要使用unionall,如果不加all关键字,MySQL会给临时表加上distinct选项,这会导致对整个临时表做唯一性检查,代价很高。26。怎么看执行计划(explain),如何理解其中各个字段的含义?
  explain是sql优化的利器,除了优化慢sql,平时的sql编写,也应该先explain,查看一下执行计划,看看是否还有优化的空间。
  直接在select语句之前增加explain关键字,就会返回执行计划的信息。
  explain
  explainid列:MySQL会为每个select语句分配一个唯一的id值selecttype列,查询的类型,根据关联、union、子查询等等分类,常见的查询类型有SIMPLE、PRIMARY。table列:表示explain的一行正在访问哪个表。type列:最重要的列之一。表示关联类型或访问类型,即MySQL决定如何查找表中的行。性能从最优到最差分别为:systemconsteqrefreffulltextrefornullindexmergeuniquesubqueryindexsubqueryrangeindexALLsystemsystem:当表仅有一行记录时(系统表),数据量很少,往往不需要进行磁盘IO,速度非常快constconst:表示查询时命中primarykey主键或者unique唯一索引,或者被连接的部分是一个常量(const)值。这类扫描效率极高,返回数据量少,速度非常快。eqrefeqref:查询时命中主键primarykey或者uniquekey索引,type就是eqref。refornullrefornull:这种连接类型类似于ref,区别在于MySQL会额外搜索包含NULL值的行。indexmergeindexmerge:使用了索引合并优化方法,查询使用了两个以上的索引。uniquesubqueryuniquesubquery:替换下面的IN子查询,子查询返回不重复的集合。indexsubqueryindexsubquery:区别于uniquesubquery,用于非唯一索引,可以返回重复值。rangerange:使用索引选择行,仅检索给定范围内的行。简单点说就是针对一个有索引的字段,给定范围检索数据。在where语句中使用bettween。。。and、、、、in等条件查询type都是range。indexindex:Index与ALL其实都是读全表,区别在于index是遍历索引树读取,而ALL是从硬盘中读取。ALL就不用多说了,全表扫描。possiblekeys列:显示查询可能使用哪些索引来查找,使用索引优化sql的时候比较重要。key列:这一列显示mysql实际采用哪个索引来优化对该表的访问,判断索引是否失效的时候常用。keylen列:显示了MySQL使用ref列:ref列展示的就是与索引列作等值匹配的值,常见的有:const(常量),func,NULL,字段名。rows列:这也是一个重要的字段,MySQL查询优化器根据统计信息,估算SQL要查到结果集需要扫描读取的数据行数,这个值非常直观显示SQL的效率好坏,原则上rows越少越好。Extra列:显示不适合在其它列的额外信息,虽然叫额外,但是也有一些重要的信息:Usingindex:表示MySQL将使用覆盖索引,以避免回表Usingwhere:表示会在存储引擎检索之后再进行过滤Usingtemporary:表示对查询结果排序时会使用一个临时表。索引
  索引可以说是MySQL面试中的重中之重,一定要彻底拿下。27。能简单说一下索引的分类吗?
  从三个不同维度对索引分类:
  索引分类
  例如从基本使用使用的角度来讲:主键索引:InnoDB主键是默认的索引,数据列不允许重复,不允许为NULL,一个表只能有一个主键。唯一索引:数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。普通索引:基本的索引类型,没有唯一性的限制,允许为NULL值。组合索引:多列值组成一个索引,用于组合搜索,效率大于索引合并28。为什么使用索引会加快查询?
  传统的查询方法,是按照表的顺序遍历的,不论查询几条数据,MySQL需要将表的数据从头到尾遍历一遍。
  在我们添加完索引之后,MySQL一般通过BTREE算法生成一个索引文件,在查询数据库时,找到索引文件进行遍历,在比较小的索引数据里查找,然后映射到对应的数据,能大幅提升查找的效率。
  和我们通过书的目录,去查找对应的内容,一样的道理。
  索引加快查询远离29。创建索引有哪些注意点?
  索引虽然是sql性能优化的利器,但是索引的维护也是需要成本的,所以创建索引,也要注意:索引应该建在查询应用频繁的字段在用于where判断、order排序和join的(on)字段上创建索引。索引的个数应该适量索引需要占用空间;更新时候也需要维护。区分度低的字段,例如性别,不要建索引。离散度太低的字段,扫描的行数降低的有限。频繁更新的值,不要作为主键或者索引维护索引文件需要成本;还会导致页分裂,IO次数增多。组合索引把散列性高(区分度高)的值放在前面为了满足最左前缀匹配原则创建组合索引,而不是修改单列索引。组合索引代替多个单列索引(对于单列索引,MySQL基本只能使用一个索引,所以经常使用多个条件查询时更适合使用组合索引)过长的字段,使用前缀索引。当字段值比较长的时候,建立索引会消耗很多的空间,搜索起来也会很慢。我们可以通过截取字段的前面一部分内容建立索引,这个就叫前缀索引。不建议用无序的值(例如身份证、UUID)作为索引当主键具有不确定性,会造成叶子节点频繁分裂,出现磁盘存储的碎片化30。索引哪些情况下会失效呢?查询条件包含or,可能导致索引失效如果字段类型是字符串,where时一定用引号括起来,否则会因为隐式类型转换,索引失效like通配符可能导致索引失效。联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。在索引列上使用mysql的内置函数,索引失效。对索引列运算(如,、、、),索引失效。索引字段上使用(!或者,notin)时,可能会导致索引失效。索引字段上使用isnull,isnotnull,可能导致索引失效。左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。MySQL优化器估计使用全表扫描要比使用索引快,则不使用索引。31。索引不适合哪些场景呢?数据量比较少的表不适合加索引更新比较频繁的字段也不适合加索引离散低的字段不适合加索引(如性别)32。索引是不是建的越多越好呢?
  当然不是。索引会占据磁盘空间索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删改操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。33。MySQL索引用的什么数据结构了解吗?
  MySQL的默认存储引擎是InnoDB,它采用的是B树结构的索引。B树:只有叶子节点才会存储数据,非叶子节点只存储键值。叶子节点之间使用双向指针连接,最底层的叶子节点形成了一个双向有序链表。
  B树索引
  在这张图里,有两个重点:最外面的方块,的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(粉色所示)和指针(黄色灰色所示),如根节点磁盘包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、4、5、65。非叶子节点只不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。叶子节点之间使用双向指针连接,最底层的叶子节点形成了一个双向有序链表,可以进行范围查询。34。那一棵B树能存储多少条数据呢?
  B树存储数据条数
  假设索引字段是bigint类型,长度为8字节。指针大小在InnoDB源码中设置为6字节,这样一共14字节。非叶子节点(一页)可以存储16384141170个这样的单元(键值指针),代表有1170个指针。
  树深度为2的时候,有11702个叶子节点,可以存储的数据为117011701621902400。
  在查找数据时一次页的查找代表一次IO,也就是说,一张2000万左右的表,查询数据最多需要访问3次磁盘。
  所以在InnoDB中B树深度一般为13层,它就能满足千万级的数据存储。35。为什么要用B树,而不用普通二叉树?
  可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数。
  为什么不用普通二叉树?
  普通二叉树存在退化的情况,如果它退化成链表,相当于全表扫描。平衡二叉树相比于二叉查找树来说,查找效率更稳定,总体的查找速度也更快。
  为什么不用平衡二叉树呢?
  读取数据的时候,是从磁盘读到内存。如果树这种数据结构作为索引,那每查找一次数据就需要从磁盘中读取一个节点,也就是一个磁盘块,但是平衡二叉树可是每个节点只存储一个键值和数据的,如果是B树,可以存储更多的节点数据,树的高度也会降低,因此读取磁盘的次数就降下来啦,查询效率就快。36。为什么用B树而不用B树呢?
  B相比较B树,有这些优势:它是BTree的变种,BTree能解决的问题,它都能解决。BTree解决的两大问题:每个节点存储更多关键字;路数更多扫库、扫表能力更强如果我们要对表进行全表扫描,只需要遍历叶子节点就可以了,不需要遍历整棵BTree拿到所有的数据。BTree的磁盘读写能力相对于BTree来说更强,IO次数更少根节点和枝节点不保存数据区,所以一个节点可以保存更多的关键字,一次磁盘加载的关键字更多,IO次数更少。排序能力更强因为叶子节点上有下一个数据区的指针,数据形成了链表。效率更加稳定BTree永远是在叶子节点拿到数据,所以IO次数是稳定的。37。Hash索引和B树索引区别是什么?B树可以进行范围查询,Hash索引不能。B树支持联合索引的最左侧原则,Hash索引不支持。B树支持orderby排序,Hash索引不支持。Hash索引在等值查询上比B树效率更高。B树使用like进行模糊查询的时候,like后面(比如开头)的话可以起到优化的作用,Hash索引根本无法进行模糊查询。38。聚簇索引与非聚簇索引的区别?
  首先理解聚簇索引不是一种新的索引,而是而是一种数据存储方式。聚簇表示数据行和相邻的键值紧凑地存储在一起。我们熟悉的两种存储引擎MyISAM采用的是非聚簇索引,InnoDB采用的是聚簇索引。
  可以这么说:索引的数据结构是树,聚簇索引的索引和数据存储在一棵树上,树的叶子节点就是数据,非聚簇索引索引和数据不在一棵树上。
  聚簇索引和非聚簇索引一个表中只能拥有一个聚簇索引,而非聚簇索引一个表可以存在多个。聚簇索引,索引中键值的逻辑顺序决定了表中相应行的物理顺序;索引,索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同。聚簇索引:物理存储按照索引排序;非聚集索引:物理存储不按照索引排序;39。回表了解吗?
  在InnoDB存储引擎里,利用辅助索引查询,先通过辅助索引找到主键索引的键值,再通过主键值查出主键索引里面没有符合要求的数据,它比基于主键索引的查询多扫描了一棵索引树,这个过程就叫回表。
  例如:selectfromuserwherename‘张三’;
  InnoDB回表40。覆盖索引了解吗?
  在辅助索引里面,不管是单列索引还是联合索引,如果select的数据列只用辅助索引中就能够取得,不用去查主键索引,这时候使用的索引就叫做覆盖索引,避免了回表。
  比如,selectnamefromuserwherename‘张三’;
  覆盖索引41。什么是最左前缀原则最左匹配原则?
  注意:最左前缀原则、最左匹配原则、最左前缀匹配原则这三个都是一个概念。
  最左匹配原则:在InnoDB的联合索引中,查询的时候只有匹配了前一个左边的值之后,才能匹配下一个。
  根据最左匹配原则,我们创建了一个组合索引,如(a1,a2,a3),相当于创建了(a1)、(a1,a2)和(a1,a2,a3)三个索引。
  为什么不从最左开始查,就无法匹配呢?
  比如有一个user表,我们给name和age建立了一个组合索引。ALTERTABLEuseraddINDEXcomidxnamephone(name,age);
  组合索引在BTree中是复合的数据结构,它是按照从左到右的顺序来建立搜索树的(name在左边,age在右边)。
  组合索引
  从这张图可以看出来,name是有序的,age是无序的。当name相等的时候,age才是有序的。
  这个时候我们使用wherename‘张三‘andage‘20‘去查询数据的时候,BTree会优先比较name来确定下一步应该搜索的方向,往左还是往右。如果name相同的时候再比较age。但是如果查询条件没有name,就不知道下一步应该查哪个节点,因为建立搜索树的时候name是第一个比较因子,所以就没用上索引。42。什么是索引下推优化?
  索引条件下推优化(IndexConditionPushdown(ICP))是MySQL5。6添加的,用于优化数据查询。不使用索引条件下推优化时存储引擎通过索引检索到数据,然后返回给MySQLServer,MySQLServer进行过滤条件的判断。当使用索引条件下推优化时,如果存在某些被索引的列的判断条件时,MySQLServer将这一部分判断条件下推给存储引擎,然后由存储引擎通过判断索引是否符合MySQLServer传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器。
  例如一张表,建了一个联合索引(name,age),查询语句:selectfromtuserwherenamelike张andage10;,由于name使用了范围查询,根据最左匹配原则:
  不使用ICP,引擎层查找到namelike张的数据,再由Server层去过滤age10这个条件,这样一来,就回表了两次,浪费了联合索引的另外一个字段age。
  没有使用ICP
  但是,使用了索引下推优化,把where的条件放到了引擎层执行,直接根据namelike张andage10的条件进行过滤,减少了回表的次数。
  使用ICP
  索引条件下推优化可以减少存储引擎查询基础表的次数,也可以减少MySQL服务器从存储引擎接收数据的次数。锁43。MySQL中有哪几种锁,列举一下?
  MySQL中的锁
  如果按锁粒度划分,有以下3种:表锁:开销小,加锁快;锁定力度大,发生锁冲突概率高,并发度最低;不会出现死锁。行锁:开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高。页锁:开销和加锁速度介于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般
  如果按照兼容性,有两种,共享锁(SLock),也叫读锁(readlock),相互不阻塞。排他锁(XLock),也叫写锁(writelock),排它锁是阻塞的,在一定时间内,只有一个请求能执行写入,并阻止其它锁读取正在写入的数据。44。说说InnoDB里的行锁实现?
  我们拿这么一个用户表来表示行级锁,其中插入了4行数据,主键值分别是1,6,8,12,现在简化它的聚簇索引结构,只保留数据记录。
  简化的主键索引
  InnoDB的行锁的主要实现如下:RecordLock记录锁
  记录锁就是直接锁定某行记录。当我们使用唯一性的索引(包括唯一索引和聚簇索引)进行等值查询且精准匹配到一条记录时,此时就会直接将这条记录锁定。例如selectfromtwhereid6forupdate;就会将id6的记录锁定。
  记录锁GapLock间隙锁
  间隙锁(GapLocks)的间隙指的是两个记录之间逻辑上尚未填入数据的部分,是一个左开右开空间。
  间隙锁
  间隙锁就是锁定某些间隙区间的。当我们使用用等值查询或者范围查询,并且没有命中任何一个record,此时就会将对应的间隙区间锁定。例如selectfromtwhereid3forupdate;或者selectfromtwhereid1andid6forupdate;就会将(1,6)区间锁定。NextkeyLock临键锁
  临键指的是间隙加上它右边的记录组成的左开右闭区间。比如上述的(1,6〕、(6,8〕等。
  临键锁
  临键锁就是记录锁(RecordLocks)和间隙锁(GapLocks)的结合,即除了锁住记录本身,还要再锁住索引之间的间隙。当我们使用范围查询,并且命中了部分record记录,此时锁住的就是临键区间。注意,临键锁锁住的区间会包含最后一个record的右边的临键区间。例如selectfromtwhereid5andid7forupdate;会锁住(4,7〕、(7,)。mysql默认行锁类型就是临键锁(NextKeyLocks)。当使用唯一性索引,等值查询匹配到一条记录的时候,临键锁(NextKeyLocks)会退化成记录锁;没有匹配到任何记录的时候,退化成间隙锁。
  间隙锁(GapLocks)和临键锁(NextKeyLocks)都是用来解决幻读问题的,在已提交读(READCOMMITTED)隔离级别下,间隙锁(GapLocks)和临键锁(NextKeyLocks)都会失效!
  上面是行锁的三种实现算法,除此之外,在行上还存在插入意向锁。InsertIntentionLock插入意向锁
  一个事务在插入一条记录时需要判断一下插入位置是不是被别的事务加了意向锁,如果有的话,插入操作需要等待,直到拥有gap锁的那个事务提交。但是事务在等待的时候也需要在内存中生成一个锁结构,表明有事务想在某个间隙中插入新记录,但是现在在等待。这种类型的锁命名为InsertIntentionLocks,也就是插入意向锁。
  假如我们有个T1事务,给(1,6)区间加上了意向锁,现在有个T2事务,要插入一个数据,id为4,它会获取一个(1,6)区间的插入意向锁,又有有个T3事务,想要插入一个数据,id为3,它也会获取一个(1,6)区间的插入意向锁,但是,这两个插入意向锁锁不会互斥。
  插入意向锁45。意向锁是什么知道吗?
  意向锁是一个表级锁,不要和插入意向锁搞混。
  意向锁的出现是为了支持InnoDB的多粒度锁,它解决的是表锁和行锁共存的问题。
  当我们需要给一个表加表锁的时候,我们需要根据去判断表中有没有数据行被锁定,以确定是否能加成功。
  假如没有意向锁,那么我们就得遍历表中所有数据行来判断有没有行锁;
  有了意向锁这个表级锁之后,则我们直接判断一次就知道表中是否有数据行被锁定了。
  有了意向锁之后,要执行的事务A在申请行锁(写锁)之前,数据库会自动先给事务A申请表的意向排他锁。当事务B去申请表的互斥锁时就会失败,因为表上有意向排他锁之后事务B申请表的互斥锁时会被阻塞。
  意向锁46。MySQL的乐观锁和悲观锁了解吗?悲观锁(PessimisticConcurrencyControl):
  悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能被改动,一个事务拿到悲观锁后,其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行。
  数据库中的行锁,表锁,读锁,写锁均为悲观锁。乐观锁(OptimisticConcurrencyControl)
  乐观锁认为数据的变动不会太频繁。
  乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,其中,版本最为常用。
  事务在从数据库中取数据时,会将该数据的版本也取出来(v1),当事务对数据变动完毕想要将其更新到表中时,会将之前取出的版本v1与数据中最新的版本v2相对比,如果v1v2,那么说明在数据变动期间,没有其他事务对数据进行修改,此时,就允许事务对表中的数据进行修改,并且修改时version会加1,以此来表明数据已被变动。
  如果,v1不等于v2,那么说明数据变动期间,数据被其他事务改动了,此时不允许数据更新到表中,一般的处理办法是通知用户让其重新操作。不同于悲观锁,乐观锁通常是由开发者实现的。47。MySQL遇到过死锁问题吗,你是如何解决的?
  排查死锁的一般步骤是这样的:
  (1)查看死锁日志showengineinnodbstatus;
  (2)找出死锁sql
  (3)分析sql加锁情况
  (4)模拟死锁案发
  (5)分析死锁日志
  (6)分析死锁结果
  当然,这只是一个简单的流程说明,实际上生产中的死锁千奇百怪,排查和解决起来没那么简单。事务48。MySQL事务的四大特性说一下?
  事务四大特性原子性:事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。一致性:指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。隔离性:多个事务并发访问时,事务之间是相互隔离的,即一个事务不影响其它事务运行效果。简言之,就是事务之间是进水不犯河水的。持久性:表示事务完成以后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。49。那ACID靠什么保证的呢?事务的隔离性是通过数据库锁的机制实现的。事务的一致性由undolog来保证:undolog是逻辑日志,记录了事务的insert、update、deltete操作,回滚的时候做相反的delete、update、insert操作来恢复数据。事务的原子性和持久性由redolog来保证:redolog被称作重做日志,是物理日志,事务提交的时候,必须先将事务的所有日志写入redolog持久化,到事务的提交操作才算完成。
  ACID靠什么保证50。事务的隔离级别有哪些?MySQL的默认隔离级别是什么?
  事务的四个隔离级别读未提交(ReadUncommitted)读已提交(ReadCommitted)可重复读(RepeatableRead)串行化(Serializable)
  MySQL默认的事务隔离级别是可重复读(RepeatableRead)。51。什么是幻读,脏读,不可重复读呢?事务A、B交替执行,事务A读取到事务B未提交的数据,这就是脏读。在一个事务范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。
  不同的隔离级别,在并发事务下可能会发生的问题:
  隔离级别脏读不可重复读幻读ReadUncommited读取未提交是是是ReadCommited读取已提交否是否RepeatableRead可重复读否否是Serialzable可串行化否否否52。事务的各个隔离级别都是如何实现的?
  读未提交
  读未提交,就不用多说了,采取的是读不加锁原理。事务读不加锁,不阻塞其他事务的读和写事务写阻塞其他事务写,但不阻塞其他事务读;
  读取已提交可重复读
  读取已提交和可重复读级别利用了ReadView和MVCC,也就是每个事务只能读取它能看到的版本(ReadView)。READCOMMITTED:每次读取数据前都生成一个ReadViewREPEATABLEREAD:在第一次读取数据时生成一个ReadView
  串行化
  串行化的实现采用的是读写都加锁的原理。
  串行化的情况下,对于同一行事务,写会加写锁,读会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。53。MVCC了解吗?怎么实现的?
  MVCC(MultiVersionConcurrencyControl),中文名是多版本并发控制,简单来说就是通过维护数据历史版本,从而解决并发访问情况下的读一致性问题。关于它的实现,要抓住几个关键点,隐式字段、undo日志、版本链、快照读当前读、ReadView。
  版本链
  对于InnoDB存储引擎,每一行记录都有两个隐藏列DBTRXID、DBROLLPTRDBTRXID,事务ID,每次修改时,都会把该事务ID复制给DBTRXID;DBROLLPTR,回滚指针,指向回滚段的undo日志。
  表隐藏列
  假如有一张user表,表中只有一行记录,当时插入的事务id为80。此时,该条记录的示例图如下:
  在这里插入图片描述
  接下来有两个DBTRXID分别为100、200的事务对这条记录进行update操作,整个过程如下:
  update操作
  由于每次变动都会先把undo日志记录下来,并用DBROLLPTR指向undo日志地址。因此可以认为,对该条记录的修改日志串联起来就形成了一个版本链,版本链的头节点就是当前记录最新的值。如下:
  MVCC
  ReadView
  对于ReadCommitted和RepeatableRead隔离级别来说,都需要读取已经提交的事务所修改的记录,也就是说如果版本链中某个版本的修改没有提交,那么该版本的记录时不能被读取的。所以需要确定在ReadCommitted和RepeatableRead隔离级别下,版本链中哪个版本是能被当前事务读取的。于是就引入了ReadView这个概念来解决这个问题。
  ReadView就是事务执行快照读时,产生的读视图,相当于某时刻表记录的一个快照,通过这个快照,我们可以获取:
  事务和ReadViewmids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。mintrxid:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是mids中的最小值。maxtrxid:表示生成ReadView时系统中应该分配给下一个事务的id值。creatortrxid:表示生成该ReadView的事务的事务id
  有了这个ReadView,这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本是否可见:如果被访问版本的DBTRXID属性值与ReadView中的creatortrxid值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。如果被访问版本的DBTRXID属性值小于ReadView中的mintrxid值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。如果被访问版本的DBTRXID属性值大于ReadView中的maxtrxid值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。如果被访问版本的DBTRXID属性值在ReadView的mintrxid和maxtrxid之间,那就需要判断一下trxid属性值是不是在mids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。
  如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。
  在MySQL中,READCOMMITTED和REPEATABLEREAD隔离级别的的一个非常大的区别就是它们生成ReadView的时机不同。
  READCOMMITTED是每次读取数据前都生成一个ReadView,这样就能保证自己每次都能读到其它事务提交的数据;REPEATABLEREAD是在第一次读取数据时生成一个ReadView,这样就能保证后续读取的结果完全一致。高可用性能54。数据库读写分离了解吗?
  读写分离的基本原理是将数据库读写操作分散到不同的节点上,下面是基本架构图:
  读写分离
  读写分离的基本实现是:数据库服务器搭建主从集群,一主一从、一主多从都可以。数据库主机负责读写操作,从机只负责读操作。数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。业务服务器将写操作发给数据库主机,将读操作发给数据库从机。55。那读写分离的分配怎么实现呢?
  将读写操作区分开来,然后访问不同的数据库服务器,一般有两种方式:程序代码封装和中间件封装。程序代码封装
  程序代码封装指在代码中抽象一个数据访问层(所以有的文章也称这种方式为中间层封装),实现读写操作分离和数据库服务器连接的管理。例如,基于Hibernate进行简单封装,就可以实现读写分离:
  业务代码封装
  目前开源的实现方案中,淘宝的TDDL(TaobaoDistributedDataLayer,外号:头都大了)是比较有名的。中间件封装
  中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。中间件对业务服务器提供SQL兼容的协议,业务服务器无须自己进行读写分离。
  对于业务服务器来说,访问中间件和访问数据库没有区别,事实上在业务服务器看来,中间件就是一个数据库服务器。
  其基本架构是:
  数据库中间件56。主从复制原理了解吗?master数据写入,更新binlogmaster创建一个dump线程向slave推送binlogslave连接到master的时候,会创建一个IO线程接收binlog,并记录到relaylog中继日志中slave再开启一个sql线程读取relaylog事件并在slave执行,完成同步slave记录自己的binglog
  主从复制57。主从同步延迟怎么处理?
  主从同步延迟的原因
  一个服务器开放个链接给客户端来连接的,这样有会有大并发的更新操作,但是从服务器的里面读取binlog的线程仅有一个,当某个SQL在从服务器上执行的时间稍长或者由于某个SQL要进行锁表就会导致,主服务器的SQL大量积压,未被同步到从服务器里。这就导致了主从不一致,也就是主从延迟。
  主从同步延迟的解决办法
  解决主从复制延迟有几种常见的方法:写操作后的读操作指定发给数据库主服务器
  例如,注册账号完成后,登录时读取账号的读操作也发给数据库主服务器。这种方式和业务强绑定,对业务的侵入和影响较大,如果哪个新来的程序员不知道这样写代码,就会导致一个bug。读从机失败后再读一次主机
  这就是通常所说的二次读取,二次读取和业务无绑定,只需要对底层数据库访问的API进行封装即可,实现代价较小,不足之处在于如果有很多二次读取,将大大增加主机的读操作压力。例如,黑客暴力破解账号,会导致大量的二次读取操作,主机可能顶不住读操作的压力从而崩溃。关键业务读写操作全部指向主机,非关键业务采用读写分离
  例如,对于一个用户管理系统来说,注册登录的业务读写操作全部访问主机,用户的介绍、爰好、等级等业务,可以采用读写分离,因为即使用户改了自己的自我介绍,在查询时却看到了自我介绍还是旧的,业务影响与不能登录相比就小很多,还可以忍受。58。你们一般是怎么分库的呢?垂直分库:以表为依据,按照业务归属不同,将不同的表拆分到不同的库中。
  垂直分库水平分库:以字段为依据,按照一定策略(hash、range等),将一个库中的数据拆分到多个库中。
  水平分库59。那你们是怎么分表的?水平分表:以字段为依据,按照一定策略(hash、range等),将一个表中的数据拆分到多个表中。垂直分表:以字段为依据,按照字段的活跃性,将表中字段拆到不同的表(主表和扩展表)中。
  表拆分60。水平分表有哪几种路由方式?
  什么是路由呢?就是数据应该分到哪一张表。
  水平分表主要有三种路由方式:范围路由:选取有序的数据列(例如,整形、时间戳等)作为路由的条件,不同分段分散到不同的数据库表中。
  我们可以观察一些支付系统,发现只能查一年范围内的支付记录,这个可能就是支付公司按照时间进行了分表。
  范围路由
  范围路由设计的复杂点主要体现在分段大小的选取上,分段太小会导致切分后子表数量过多,增加维护复杂度;分段太大可能会导致单表依然存在性能问题,一般建议分段大小在100万至2000万之间,具体需要根据业务选取合适的分段大小。
  范围路由的优点是可以随着数据的增加平滑地扩充新的表。例如,现在的用户是100万,如果增加到1000万,只需要增加新的表就可以了,原有的数据不需要动。范围路由的一个比较隐含的缺点是分布不均匀,假如按照1000万来进行分表,有可能某个分段实际存储的数据量只有1000条,而另外一个分段实际存储的数据量有900万条。Hash路由:选取某个列(或者某几个列组合也可以)的值进行Hash运算,然后根据Hash结果分散到不同的数据库表中。
  同样以订单id为例,假如我们一开始就规划了4个数据库表,路由算法可以简单地用id4的值来表示数据所属的数据库表编号,id为12的订单放到编号为50的子表中,id为13的订单放到编号为61的字表中。
  Hash路由
  Hash路由设计的复杂点主要体现在初始表数量的选取上,表数量太多维护比较麻烦,表数量太少又可能导致单表性能存在问题。而用了Hash路由后,增加子表数量是非常麻烦的,所有数据都要重分布。Hash路由的优缺点和范围路由基本相反,Hash路由的优点是表分布比较均匀,缺点是扩充新的表很麻烦,所有数据都要重分布。配置路由:配置路由就是路由表,用一张独立的表来记录路由信息。同样以订单id为例,我们新增一张orderrouter表,这个表包含orderjd和tablejd两列,根据orderjd就可以查询对应的tableid。
  配置路由设计简单,使用起来非常灵活,尤其是在扩充表的时候,只需要迁移指定的数据,然后修改路由表就可以了。
  配置路由
  配置路由的缺点就是必须多查询一次,会影响整体性能;而且路由表本身如果太大(例如,几亿条数据),性能同样可能成为瓶颈,如果我们再次将路由表分库分表,则又面临一个死循环式的路由算法选择问题。61。不停机扩容怎么实现?
  实际上,不停机扩容,实操起来是个非常麻烦而且很有风险的操作,当然,面试回答起来就简单很多。第一阶段:在线双写,查询走老库建立好新的库表结构,数据写入久库的同时,也写入拆分的新库数据迁移,使用数据迁移程序,将旧库中的历史数据迁移到新库使用定时任务,新旧库的数据对比,把差异补齐第一阶段第二阶段:在线双写,查询走新库完成了历史数据的同步和校验把对数据的读切换到新库第二阶段第三阶段:旧库下线旧库不再写入新的数据经过一段时间,确定旧库没有请求之后,就可以下线老库
  第三阶段62。常用的分库分表中间件有哪些?shardingjdbcMycat63。那你觉得分库分表会带来什么问题呢?
  从分库的角度来讲:事务的问题
  使用关系型数据库,有很大一点在于它保证事务完整性。
  而分库之后单机事务就用不上了,必须使用分布式事务来解决。跨库JOIN问题
  在一个库中的时候我们还可以利用JOIN来连表查询,而跨库了之后就无法使用JOIN了。
  此时的解决方案就是在业务代码中进行关联,也就是先把一个表的数据查出来,然后通过得到的结果再去查另一张表,然后利用代码来关联得到最终的结果。
  这种方式实现起来稍微比较复杂,不过也是可以接受的。
  还有可以适当的冗余一些字段。比如以前的表就存储一个关联ID,但是业务时常要求返回对应的Name或者其他字段。这时候就可以把这些字段冗余到当前表中,来去除需要关联的操作。
  还有一种方式就是数据异构,通过binlog同步等方式,把需要跨库join的数据异构到ES等存储结构中,通过ES进行查询。
  从分表的角度来看:跨节点的count,orderby,groupby以及聚合函数问题
  只能由业务代码来实现或者用中间件将各表中的数据汇总、排序、分页然后返回。数据迁移,容量规划,扩容等问题
  数据的迁移,容量如何规划,未来是否可能再次需要扩容,等等,都是需要考虑的问题。ID问题
  数据库表被切分后,不能再依赖数据库自身的主键生成机制,所以需要一些手段来保证全局主键唯一。还是自增,只不过自增步长设置一下。比如现在有三张表,步长设置为3,三张表ID初始值分别是1、2、3。这样第一张表的ID增长是1、4、7。第二张表是2、5、8。第三张表是3、6、9,这样就不会重复了。UUID,这种最简单,但是不连续的主键插入会导致严重的页分裂,性能比较差。分布式ID,比较出名的就是Twitter开源的sonwflake雪花算法运维64。百万级别以上的数据如何删除?
  关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增改删的执行效率。
  所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。所以我们想要删除百万数据的时候可以先删除索引然后删除其中无用数据删除完成后重新创建索引创建索引也非常快65。百万千万级大表如何添加字段?
  当线上的数据库数据量到达几百万、上千万的时候,加一个字段就没那么简单,因为可能会长时间锁表。
  大表添加字段,通常有这些做法:通过中间表转换过去创建一个临时的新表,把旧表的结构完全复制过去,添加字段,再把旧表数据复制过去,删除旧表,新表命名为旧表的名称,这种方式可能回丢掉一些数据。用ptonlineschemachangeptonlineschemachange是percona公司开发的一个工具,它可以在线修改表结构,它的原理也是通过中间表。先在从库添加再进行主从切换如果一张表数据量大且是热表(读写特别频繁),则可以考虑先在从库添加,再进行主从切换,切换后再将其他几个节点上添加字段。66。MySQL数据库cpu飙升的话,要怎么处理呢?
  排查过程:
  (1)使用top命令观察,确定是mysqld导致还是其他原因。
  (2)如果是mysqld导致的,showprocesslist,查看session情况,确定是不是有消耗资源的sql在运行。
  (3)找出消耗高的sql,看看执行计划是否准确,索引是否缺失,数据量是否太大。
  处理:
  (1)kill掉这些线程(同时观察cpu使用率是否下降),
  (2)进行相应的调整(比如说加索引、改sql、改内存参数)
  (3)重新跑这些SQL。
  其他情况:
  也有可能是每个sql消耗资源并不多,但是突然之间,有大量的session连进来导致cpu飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等
  原文链接:https:mp。weixin。qq。comszSTyZ8CFalwAYSB0PN6wA

员工谈苹果是否考虑让iPad运行macOS两个平台是独一无二苹果营销员工ScottBroderick和显示工程师VincentGu最近接受了AppleBitzXL播客主持人BrianTong的采访,谈及了为什么macOS不会出现在iPa……京沪两地法学生起诉苹果公司,买iPhone12Pro凭什么不感谢IT之家网友初雨滋的线索投递!IT之家10月26日消息,据上海法制报报道,近日,因苹果新产品不再赠送适配充电器,来自北京化工大学、东华大学的学生们组队将苹果公司告上法……消息称M1XMacBookPro为刘海屏,苹果早已申请相关专IT之家10月17日消息,苹果将于北京时间10月19日凌晨1点举办发布会,预计将发布搭载M1X芯片的MacBookPro新品,以及AirPods3耳机等。多方爆料称,新款Mac……19912021年,旅行三十年中的演变旅行装备发生了怎样的变化?一次性胶卷相机GoPro旅途中胶卷用完总是很痛苦,尤其令人沮丧的是照片冲洗出来,发现大部分都不堪入目。而现在,有很多其他的相机技术可以捕捉……苹果iOS15。0。2正式版已修复1个零日漏洞,但并未感谢安IT之家10月14日消息,据9to5Mac报道,上个月,安全研究员DenisTokarev(又名illusionofchaos)分享了他向苹果公司报告3个零日iOS漏洞的经历,……供应链回应苹果iPhone13减产订单没有太大改变,组装厂生IT之家10月14日消息,此前彭博社报道称,因上游芯片缺料受限,苹果iPhone13今年将减产千万部,总产能低于预期。苹果目前仍未对这一传言评论,而iPhone13系列两……恭喜!中国跳水奥运冠军女神升级当妈,老公威猛,2人夫妻相十足还记得2012年伦敦奥运会十米台双人冠军汪皓吗?28岁的这位奥运冠军,升级成为了母亲,她晒出了自己大肚子的照片!作为汪皓的搭档,奥运5金王陈若琳却还没有结婚。2012年的……王者荣耀12月3日体验服停机更新内容亲爱的召唤师:为了增加版本的稳定性,我们计划在2021年12月3日10:3012:30对《王者荣耀》体验服进行停机维护。【更新时间】12月3日10:3012:30(……苹果悄悄地延长了AirPodsPro维修计划,以解决爆裂声降IT之家10月14日消息,早在2020年10月,苹果就推出了一项服务计划来解决AirPodsPro可能出现的问题,例如静电噪音、噼啪声或主动降噪问题。当时,苹果表示该计划……如何取个好名字孔子曰名不正则言不顺,苏东坡也说世间唯名实不可欺,道出了姓名对人的重要性,更体现了诸多先贤的哲学内涵。取名之事乃人生之大事,民间流传的取名习俗也是多种多样,主要的取名习俗……苹果证实新上架的140W电源适配器为其首款GaN充电器IT之家10月19日消息,据TheVerge报道,苹果公司向其证实,新上架的140WUSBC电源适配器是苹果首款GaN充电器。与传统充电器相比,GaN充电器的更小、更轻,……AMDRyzen攻势猛烈x86处理器市场变天Intel市占首来自市场调查研究机构MercuryResearch的最新数据显示,虽然于今年第二季中,桌上型处理器销售量创下30年来新低,但就个别品牌而言,AMD是相对胜利的一方,其于笔电、桌……
带您一起来认识开曼群岛在司马南先生的一个视频里,谈到了一个群岛的名字:那就是开曼群岛。它的具体位置在哪里呢?寻找开曼正好我家的墙上挂着的一幅新版彩色世界地图,我驻留在它的面前,仔细观看、搜索,……男人一生中最忘不掉的女人,并不是自己的妻子男人的一生中,难免会遇到许多女人。有些女人只是过客,而有些女人则会深深地印在男人的心中,成为他们一生中最难以忘怀的人。然而,这些人并不一定是男人的妻子,或许只是一段短暂的经历,……玫瑰绽放!中国U20女足60大胜菲律宾北京时间3月8日下午17:00,在U20女足亚洲杯预选赛,中国U20女足VS菲律宾U20女足的比赛中,中国U20女足凭借上下半场各打进3个进球,中国U20女足6:0大胜菲律宾U……成都亟待培育电子产业高新技术区!三环路以西,光华大道以北,红光大道以南,二绕以东,划定一个新的高新技术区,命名为蜀都电子信息高新技术区,简称蜀都高新区。综合保税区、高新西区全部和金牛区、郫都区、温江区部分整合……华引芯发布全新ADB矩阵光源模组,领跑智能车灯国产化赛道受全球汽车智能化浪潮驱动,汽车照明正从以往单一照明迈向智能照明、数字投影、互动娱乐的多元发展,ADB智能矩阵大灯由此应运而生。与此同时,中国新能源汽车的强势崛起更为国内光源企业……冬季养生,吃哪些五谷杂粮好《黄帝内经》说:冬不藏精,春病必温。这句话的意思是,冬天没有把阴津和阳气封藏好,过度消耗,会埋下来年的疾病的祸根。例如疲乏无力、手脚冰凉、反复的感冒、上火等。到了冬天,人体的阳……9月警察预备党员转正思想汇报篇一敬爱的党组织:您好!我叫XXX,19xx年X月XX日生,20xx年x月郑重地向党组织递交了入党申请书,20xx年被党组织吸收为入党积极分子考察对象,20x……1500字的读书心得体会范文教育成功的秘密在于尊重学生,只有尊重学生的人格,顾及学生的自尊心,学生才能信任老师,在此分享1500字的读书心得体会范文。下面是品学网小编为大家收集整理的1500字的读书心得体……保安会议记录内容范文6篇召开保安人员工作会议,保安会议有哪些内容呢?将保安会议做一个简要记录。本文是保安会议记录内容的范文,仅供参考。保安会议记录内容范文篇一:时间:20xx年3月8日地点……女性健康讲座个人思想总结篇一:我听了韩学荣教授的心理健康讲座感觉受益匪浅收获很多。韩老师从健康的定义、健康的标准、健康与不健康的问题等几个方面展开了讲述,感觉老师讲的这些都很贴切实际,很实……优秀教师转作风树形象心得优秀教师转作风树形象个人总结教师形象是公众认识教师最直接的窗口,教师形象的变迁不仅反映了教师自身能力、素质、价值观等各方面的改变,而且折射出社会的发展变化与主流意识形态的变更。接下来就跟品学网小编一起去了……骨科护士长述职报告怎么写?【篇一】尊敬的各位领导、亲爱的同事们你们好!在过去的一年里,本人能够踏实工作,锐意进取,认真钻研工作方法,总结工作经验,立足本职岗位,带领全科室所有护理人员,用心参……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网