MySQL面试问题包含答案仅参考

  • ,理论和总结部分:

1:引擎MyISAM与innoDB简介:

  • **MyISAM:**默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method(有索引的顺序访问方法)的首字母缩写,它是存储记录和文件的标准方法,事务不安全,不支持外键,适合执行大量的select和insert。此引擎已不常用,且外键也不常用了。
  • **InnoDB:**支持事务安全,支持外键,支持行锁。适合执行大量的update和insert,适合高并发高QPS场景。

2:关于MyisAM和innodb的两者索引的疑问和对比

  • MyISAM是非聚集索引,使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址。
    MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。
  • Innodb是聚集索引, 虽然InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。第一个重大区别是InnoDB的数据文件本身就是索引文件, 这棵树的叶节点data域保存了完整的数据记录。
    但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
    因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有)
    1)如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键
    2)如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。(隐含字段)
    简单说:
    如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择其作为聚集索引;如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。所以innodb不需要myi文件。
  • 聚集索引与非聚集索引的区别
    非聚集索引和聚集索引的主要区别在于: 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据。
    聚集索引和非聚集索引的根本区别是:表记录的排列顺序和与索引的排列顺序是否一致。 聚集索引(innodb)的叶节点就是数据节点,而非聚集索引(myisAM)的叶节点仍然是索引节点,只不过其包含一个指向对应数据块的指针。

3:innodb为什么要用自增id作为主键:

  • 如果一个表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页
  • 如果使用非自增主键(如果身份证号、单元号、车位号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置, 频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE(optimize table)来重建表并优化填充页面。

3:关于分库与分表设计分片:

  • 分库与分表的目的在于,减小数据库的单库单表负担,提高查询性能,缩短查询时间。
  • 分表总作用:减少数据库的单表负担,将压力分散到不同的表上,同时因为不同的表上的数据量少了,起到提高查询性能,缩短查询时间的作用,此外,可以很大的缓解表锁的问题。
  • 分表策略可以归纳为垂直拆分和水平拆分:
  • 水平分表:包括按随机性质的分表即-取模分表,按连续性分表-时间维度分表
  • 垂直分表:将不常用的字段单独拆分到另外一张扩展表. 将大文本的字段单独拆分到另外一张扩展表, 将不经常修改的字段放在同一张表中,将经常改变的字段放在另一张表中。对于海量用户场景,可以考虑取模分表,数据相对比较均匀,不容易出现热点和并发访问的瓶颈。
  • 库内分表:仅是解决了单表数据过大的问题,但并没有把单表的数据分散到不同的物理机上,因此并不能减轻 MySQL 服务器的压力,仍然存在同一个物理机上的资源竞争和瓶颈,包括 CPU、内存、磁盘 IO、网络带宽等。
  • 分库与分表带来的分布式困境与应对之策:
    (1),数据迁移与扩容问题----一般做法是通过程序先读出数据,然后按照指定的分表策略再将数据写入到各个分表中。
    (2),分页与排序问题----需要在不同的分表中将数据进行排序并返回,并将不同分表返回的结果集进行汇总和再次排序,最后再返回给用户。
    (3),分布式全局唯一ID:UUID、GUID等

4:事务四大特性(ACID)原子性、一致性、隔离性、持久性

事务特性释义:

  • 原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • **一致性:**在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  • **隔离性:**数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。**事务隔离分为不同级别:**包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • **持久性:**事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
* 其他版本关于事务四大特性的解释:
其他版本的
原子性(Atomicity)
* 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
一致性(Consistency)
* 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到。
隔离性(Isolation)
* 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。   持久性(Durability)
* 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

5:关于事务的并发方面:事务的隔离级别-每个级别会引发什么问题,那MySQL默认是哪个级别?

  • 事务的隔离级别如图:
    MySQL面试问题包含答案仅参考_第1张图片
    *事务隔离级别释义:
    (1),读未提交: 另外一个事务修改了数据,但尚未提交,而本事务中的select会读到这些未被提交的脏数据。
    (2),不可重复读: 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
    (3),可重复读: 在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象.
    (4),串行化: 并发事务之间是串行化的,通常意味着读取需要获取共享读锁,更新需要获取排他写锁,如果 SQL 使用 WHERE 语句,还会获取区间锁(MySQL 以 GAP 锁形式实现,可重复读级别中默认也会使用),这是最高的隔离级别,在这个隔离级别下,不会产生任何异常。并发的事务,就像事务是在一个个按照顺序执行一样。
    (5),读未提交: 就是一个事务能够看到其他事务尚未提交的修改,允许脏读出现。
    (6),读已提交: 事务能够看到的数据都是其他事务已经提交的修改,也就是保证不会看到任何中间性状态,当然脏读也不会出现。
    (7),可重复读:保证同一个事务中多次读取的数据是一致的,这是 MySQL InnoDB 引擎的默认隔离级别
  • 事务隔离级别出现的问题们释义:
    (1),脏读: 是指在一个事务处理过程中读取了另一个事务未提交的数据。
    场景:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
    (2),不可重复读: 对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值。场景:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
    (3),幻读: 事务非独立执行时发生的一种现象,即在一个事务读的过程中,另外一个事务可能插入了新数据记录,影响了该事务读的结果。幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。场景:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作 这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。 而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有跟没有修改一样,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
    总结:
    (1)从理论上来说, 事务应该彼此完全隔离, 以避免并发事务所导致的问题,然而, 那样会对性能产生极大的影响, 因为事务必须按顺序运行, 在实际开发中, 为了提升性能, 事务会以较低的隔离级别运行, 事务的隔离级别可以通过隔离事务属性指定。
    (2)不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

6:MySQL常见的存储引擎InnoDB、MyISAM的区别?

(1)事务支持方面: MyISAM不支持事务,InnoDB支持事务。
(2)锁级别: MyISAM 表级锁,InnoDB 行级锁及外键约束。
(注意:MySQL表级锁有两种模式:表共享锁和表独占写锁)
(3)是否存储表的总行数: MyISAM存储表的总行数,InnoDB不存储表的总行数。
(4)是否聚集索引,B+树叶子存储的是指针还是数据本身: MyISAM采用非聚集索引,B+Tree叶子存储指向数据文件的指针。 InnoDB主键索引采用聚集索引,B+Tree叶子存储数据。

  • MyISAM和InnoDB两种存储引擎的适用场景:
    MyISAM适合:insert插入不频繁,查询非常频繁,如果执行大量的select,此引擎适合,且本情形下没有事务。
    InnoDB适合:极高可靠性,要求事务机制,表update更新和select查询都相当的频繁,适合大量的insert和update。
    **但是注意,**高可用高并发的今天,为了那点查询效率,不值得牺牲事务,所以,MySQL,研究InnoDB就对了,推荐国人的一本书:《MySQL技术内幕InnoDB存储引擎》。

7:数据库三大范式,你如何根据某个场景设计数据表?

  • 第一范式:确保每列保持原子性
    第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
    第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。
  • 第二范式:确保表中的每列都和主键相关
    第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
    比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键。
  • 第三范式:确保每列都和主键列直接相关,而不是间接相关
    第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
    比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。
    遵循范式的好处: 可以尽量得减少数据冗余 缺点:对于查询需要多个表进行关联,更难进行索引优化。
    不遵循范式的好处:
    优点:可以减少表得关联 。
    缺点:数据冗余以及数据异常。

8:关于MySQL 索引以及使用的注意事项:

MySQL 索引通常是被用于提高 WHERE 条件的数据行匹配时的搜索速度,在索引的使用过程中,存在一些使用细节和注意事项。
(1)函数,运算,否定操作符,连接条件,多个单列索引,最左前缀原则,范围查询,不会包含有NULL值的列,like 语句不要在列上使用函数和进行运算。
(2)不要在列上使用函数,这将导致索引失效而进行全表扫描。

select * from news where year(publish_time) < 2017

为了使用索引,防止执行全表扫描,可以进行改造:

select * from news where publish_time < '2017-01-01'

还有一个建议,不要在列上进行运算,这也将导致索引失效而进行全表扫描。

select * from news where id / 100 = 1

为了使用索引,防止执行全表扫描,可以进行改造。

select * from news where id = 1 * 100

(3)尽量避免使用 != 或 not in或 <> 等否定操作符
应该尽量避免在 where 子句中使用 != 或 not in 或 <> 操作符,因为这几个操作符都会导致索引失效而进行全表扫描。尽量避免使用 or 来连接条件
应该尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描。

select * from news where id = 1 or id = 2

(4)多个单列索引并不是最佳选择
MySQL 只能使用一个索引,会从多个索引中选择一个限制最为严格的索引,因此,为多个列创建单列索引,并不能提高 MySQL 的查询性能。
假设,有两个单列索引,分别为 news_year_idx(news_year) 和 news_month_idx(news_month)。现在,有一个场景需要针对资讯的年份和月份进行查询,那么,SQL 语句可以写成:

select * from news where news_year = 2017 and news_month = 1

事实上,MySQL 只能使用一个单列索引。为了提高性能,可以使用复合索引 news_year_month_idx(news_year, news_month) 保证 news_year 和 news_month 两个列都被索引覆盖。
(5)复合索引的最左前缀原则
复合索引遵守“最左前缀”原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用。因此,在复合索引中索引列的顺序至关重要。如果不是按照索引的最左列开始查找,则无法使用索引。
假设,有一个场景只需要针对资讯的月份进行查询,那么,SQL 语句可以写成:

select * from news where news_month = 1

此时,无法使用 news_year_month_idx(news_year, news_month) 索引,因为遵守“最左前缀”原则,在查询条件中没有使用复合索引的第一个字段,索引是不会被使用的。
(6)范围查询对多列查询的影响
查询中的某个列有范围查询,则其右边所有列都无法使用索引优化查找。
举个例子,假设有一个场景需要查询本周发布的资讯文章,其中的条件是必须是启用状态,且发布时间在这周内。那么,SQL 语句可以写成:

select * from news where publish_time >= '2017-01-02' and publish_time <= '2017-01-08' and enable = 1

这种情况下,因为范围查询对多列查询的影响,将导致news_publish_idx(publish_time, enable) 索引中 publish_time 右边所有列都无法使用索引优化查找。换句话说,news_publish_idx(publish_time, enable) 索引等价于 news_publish_idx(publish_time) 。
,对于这种情况,我的建议:对于范围查询,务必要注意它带来的副作用,并且尽量少用范围查询,可以通过曲线救国的方式满足业务场景。
例如,上面案例的需求是查询本周发布的资讯文章,因此可以创建一个news_weekth 字段用来存储资讯文章的周信息,使得范围查询变成普通的查询,SQL 可以改写成:

select * from news where news_weekth = 1 and enable = 1

然而,并不是所有的范围查询都可以进行改造,对于必须使用范围查询但无法改造的情况,我的建议:不必试图用 SQL 来解决所有问题,可以使用其他数据存储技术控制时间轴,例如 Redis 的 SortedSet 有序集合保存时间,或者通过缓存方式缓存查询结果从而提高性能。
(7)索引不会包含有NULL值的列
只要列中包含有 NULL 值都将不会被包含在索引中,复合索引中只要有一列含有 NULL值,那么这一列对于此复合索引就是无效的。
因此,在数据库设计时,除非有一个很特别的原因使用 NULL 值,不然尽量不要让字段的默认值为 NULL。
(8)隐式转换的影响
当查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换带来的影响就是可能导致索引失效而进行全表扫描。下面的案例中,date_str 是字符串,然而匹配的是整数类型,从而发生隐式转换。

select * from news where date_str = 201701

因此,要谨记隐式转换的危害,时刻注意通过同类型进行比较。
(9)like 语句的索引失效问题
like 的方式进行查询,在 like “value%” 可以使用索引,但是对于 like “%value%” 这样的方式,执行全表查询,这在数据量小的表,不存在性能问题,但是对于海量数据,全表扫描是非常可怕的事情。所以,根据业务需求,考虑使用 ElasticSearch 或 Solr 是个不错的方案。
(10)覆盖索引的好处
如果一个索引包含所有需要的查询的字段的值,直接根据索引的查询结果返回数据,而无需读表,能够极大的提高性能。因此,可以定义一个让索引包含的额外的列,即使这个列对于索引而言是无用的。

9:SQL的优化问题

SQL优化是一个分析,优化,再分析,再优化的过程。站在执行计划的角度来说,我们这个过程,就是在不断的减少rows(行\表中的记录)的数量。

  • SQL优化建议:
    1.建索引
    2.减少表之间的关联
    3.优化 sql,尽量让 sql 很快定位数据,不要让sql 做全表查询,应该走索引,把数据 量大的表排在前面
    4.简化查询字段,没用的字段不要,已经对返回结果的控制,尽量返回少量数据
    5.尽量用PreparedStatement 来查询,不要用 Statement
    6.不要在列上使用函数和进行运算
    7、不要在列上使用函数,这将导致索引失效而进行全表扫描。
    8、尽量避免使用 != 或 not in或 <> 等否定操作符
    9、尽量避免使用 or 来连接条件
    10、多个单列索引并不是最佳选择,复合索引的最左前缀原则
    11、查询中的某个列有范围查询,则其右边所有列都无法使用索引优化查找。
    12、索引不会包含有NULL值的列
    13、当查询条件左右两侧类型不匹配的时候会发生隐式转换,隐式转换带来的影响就是可能导致索引失效而进行全表扫描。
  • like 语句的索引失效问题的应对方案步骤:
    0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
    1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
    2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
    3.order by limit 形式的sql语句让排序的表优先查
    4.了解业务方使用场景
    5.加索引时参照建索引的几大原则
    6.观察结果,不符合预期继续从0分析

10: MySQL 的性能优化

0、为搜索字段创建索引(比如where搜索字段)
1、避免使用select * ,写SQL时候列出需要查询的字段
2、分表要垂直分割。
3、选择正确的存储引擎(InnoDB天下第一)
优化顺序步骤:
1.SQL语句及索引的优化
2. 数据库表结构的优化
3.系统配置的优化
4.硬件的优化

11: 数据库悲观锁和乐观锁的原理和应用场景

  • **悲观锁:**先获取锁,再进行业务操作,一般就是利用类似 SELECT … FOR UPDATE 这样的语句,对数据加锁,避免其他事务意外修改数据。
    当数据库执行select … for update时会获取被select中的数据行的行锁,select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。

  • **乐观锁:**先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过。Java 并发包中的 AtomicFieldUpdater 类似,也是利用 CAS 机制,并不会对数据加锁,而是通过对比数据的时间戳或者版本号,来实现乐观锁需要的版本判断。

12: 索引是什么?MySQL为什么使用B+树,而不是使用其他?B+树的特点

  • 索引是帮助MySQL高效获取数据的数据结构。索引:排好序的快速查找数据结构!索引会影响where后面的查找,和order by 后面的排序。
  • B+Tree索引(平衡多路查找树)
    是B-Tree的改进版本,同时也是数据库索引索引所采用的存储结构。数据都在叶子节点上,并且增加了顺序访问指针,每个叶子节点都指向相邻的叶子节点的地址。B-Tree需要获取所有节点,相比之下B+Tree效率更高。B+树索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问;
  • Hash索引
    hash:虽然可以快速定位,但是没有顺序,IO复杂度高。
    二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且IO代价高。
  • 红黑树:
    树的高度随着数据量增加而增加,IO代价高。
  • 为什么说B±tree比B 树更适合实际应用中操作系统的文件索引和数据库索引?
    B+tree的磁盘读写代价更低,B+tree的查询效率更加稳定。
    数据库索引采用B+树而不是B树的主要原因:B+树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而B树只能中序遍历所有节点,效率太低。
  • B+树的特点:
    (1)所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
    (2)不可能在非叶子结点命中;
    (3)非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;

13: 创建索引时需要注意什么

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

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

  • **索引字段越小越好:**数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

  • 唯一、不为空、经常被查询的字段 的字段适合建索引。

14: char和varchar的区别:

(1)char的长度是不可变的,用空格填充到指定长度大小,而varchar的长度是可变的。
(2)char的存取数度还是要比varchar要快得多
(3)char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。varchar的存储方式是:对每个英文字符占用2个字节,汉字也占用2个字节。

15:函数 NOW()和CURRENT_DATE()有什么区别

NOW()命令用于显示当前年份,月份,日期,小时,分钟和秒。
CURRENT_DATE()仅显示当前年份,月份和日期。

16:MySQL数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化

a. 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
b. 选择合适的表字段数据类型和存储引擎,适当的添加索引。
c. mysql库主从读写分离。
d. 找规律分表,减少单表中的数据量提高查询速度。
e。添加缓存机制,比如memcached,apc等。
f. 不经常改动的页面,生成静态页面。
g. 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.

17:各种索引的概念:索引,主键,唯一索引,联合索引,索引分类索引分类: Mysql常见索引有:主键索引、唯一索引、普通索引、全文索引、组合索引.{按聚集分类:聚集索引和非聚集索引}

**索引( 普通索引):**不允许有空值,指字段 唯一、不为空值 的列
**唯一索引:**唯一索引可以保证数据记录的唯一性,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。唯一索引允许空值( 索引列的所有值都只能出现一次,即必须唯一)
**主键:**是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字 PRIMARY KEY 来创建。
**外键:**表的外键是另一表的主键,
**组合索引:**索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引。
CREATE INDEX index_name ON table_name (column_list)
全文索引: 全文索引的索引类型为FULLTEXT, 可以在VARCHAR或者TEXT类型的列上创建。
单列索引与多列索引

18:建立索引的使用场景

  • 应当在最频繁使用的、用以缩小查询范围的字段,需要排序的字段上建立索引。
  • 不宜建立索引的字段列:
    1)对于查询中很少涉及的列或者重复值比较多的列
    2)对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等。

19:Myql中的事务回滚机制,持久性,隔离级别的实现

在 MySQL 中,恢复机制是通过回滚日志(undo log)实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后在对数据库中的对应行进行写入。 当事务已经被提交之后,就无法再次回滚了回滚日志作用:
1)能够在发生错误或者用户执行 ROLLBACK 时提供回滚相关的信息
2) 在整个系统发生崩溃、数据库进程直接被杀死后,当用户再次启动数据库进程时,还能够立刻通过查询回滚日志将之前未完成的事务进行回滚,这也就需要回滚日志必须先于数据持久化到磁盘上,是我们需要先写日志后写数据库的主要原因。
MySQL 使用重做日志(redo log)实现事务的持久性在数据库中,这两种日志经常都是一起工作的.
隔离级别的实现:
数据库对于隔离级别的实现就是使用并发控制机制对在同一时间执行的事务进行控制,限制不同的事务对于同一资源的访问和更新.锁: 共享锁(Shared)和互斥锁(Exclusive),前者也叫读锁,后者叫写锁

时间戳:
使用时间戳实现事务的隔离性时,往往都会使用乐观锁,先对数据进行修改,在写回时再去判断当前值,也就是时间戳是否改变过,如果没有改变过,就写入,否则,生成一个新的时间戳并再次更新数据

20:说一说drop、delete与truncate的区别

drop、delete、truncate都表示删除,但是三者有一些差别:

  • Delete用来删除表的全部或者一部分数据行,执行delete之后,用户需要提交(commmit)或者回滚(rollback)来执行删除或者撤销删除。会触发这个表上所有的delete触发器
  • Truncate删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器,TRUNCATE比delete更快,占用的空间更小;
  • Drop命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的DML触发器也不会被触发,这个命令也不能回滚。

因此,在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate。

21:什么是视图和游标:

  • 视图是一种虚拟的表,通常是有一个表或者多个表的行或列的子集,具有和物理表相同的功能。
  • 游标是对查询出来的结果集作为一个单元来有效的处理。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。

22:什么是存储过程?用什么来调用

存储过程是一个预编译的 SQL 语句, 使用存储过程比单纯 SQL 语句执行要快。
调用: 1)可以用一个命令对象来调用存储过程。 2)可以供外部程序调用,比如: java 程序

23:内连接、自连接、外连接(左、右、全)、交叉连接的区别。内连接:只有两个元素表相匹配的才能在结果集中显示。

外连接: 左外连接: 左边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
**右外连接:**右边为驱动表,驱动表的数据全部显示,匹配表的不匹配的不会显示。
**全外连接:**连接的表中不匹配的数据全部会显示出来。
交叉连接: 笛卡尔效应,显示的结果是链接表数的乘积。
实际

  • ,理论和使用场景部分:

24:MySQL的复制原理以及流程:

基本原理流程,3个线程以及之间的关联:
(1),主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;
(2),从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进 自己的relay log中;
(3),从:sql执行线程——执行relay log中的语句;

25:MySQL中存储引擎myisam与innodb的区别,特别指出innodb的四大特性,这两个引擎select count(*) 查询所有记录行数谁更快,为何?

  • 两个引擎的区别:
    (1)InnoDB支持事务,MyISAM不支持事务。
    (2)InnoDB支持行级锁,MyISAM支持表级锁。
    (3)InnoDB支持MVCC,MyISAM不支持。(Multi-Version Concurrency Control,多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。)
    (4)InnoDB支持外键,MyISAM不支持。
    (5)InnoDB不支持全文index索引,MyISAM支持。
  • innodb的四大特性:
    插入缓冲(insert buffer),
    二次写(double write),
    自适应哈希索引(ahi),
    预读(read ahead)。
  • 这两个引擎select count(*) 查询所有记录行数谁更快:
    myisam更快,因为myisam内部维护了一个计数器,可以直接调取。

26:MySQL中varchar与char的区别以及varchar(50)中的50代表的涵义(1)、varchar与char的区别

char是一种固定长度的类型,varchar则是一种可变长度的类型
(2)、varchar(50)中50的涵义?
最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)
(3)、int(20)中20的涵义?
是指显示字符的长度
但要加参数的,最大为255,比如它是记录行数的id,插入10笔资料,它就显示00000000001 ~~~00000000010,当字符的位数超过11,它也只显示11位,如果你没有加那个让它未满11位就前面加0的参数,它不会在前面加0
20表示最大显示宽度为20,但仍占4字节存储,存储范围不变;
(4)、mysql为什么这么设计?
对大多数应用没有意义,只是规定一些工具用来显示字符的个数;int(1)和int(20)存储和计算均一样;

27:innodb的事务与日志的实现方式

  • (1)有多少种日志?
    错误日志:记录出错信息,也记录一些警告信息或者正确的信息。
    查询日志:记录所有对数据库请求的信息,不论这些请求是否得到了正确的执行。
    慢查询日志:设置一个阈值,将运行时间超过该值的所有SQL语句都记录到慢查询的日志文件中。
    二进制日志:记录对数据库执行更改的所有操作。
    中继日志:
    事务日志:
    (2)事务的隔离级别:
    读未提交
    读已提交
    可重复读
    串行
    (3)事务如何通过日志来实现的?
    事务日志是通过redo和innodb的存储引擎日志缓冲(Innodb log buffer)来实现的,当开始一个事务的时候,会记录该事务的lsn(log sequence number)号;
    当事务执行时,会往InnoDB存储引擎的日志的日志缓存里面插入事务日志;当事务提交时,必须将存储引擎的日志缓冲写入磁盘(通过innodb_flush_log_at_trx_commit来控制),也就是写数据前,需要先写日志。这种方式称为“预写日志方式”。

28:MySQL数据库cpu飙升到500%的话他怎么处理?

(1)、没有经验的,可以不问;
(2)、有经验的,问他们的处理思路。
列出所有进程 show processlist 观察所有进程 多秒没有状态变化的(干掉)
查看超时日志或者错误日志 (做了几年开发,一般会是查询以及大批量的插入会导致cpu与i/o上涨,当然不排除网络状态突然断了,导致一个请求服务器只接受到一半,比如where子句或分页子句没有发送,当然的一次被坑经历)。

29:SQL优化

(1)、explain出来的各种item的意义;
select_type
表示查询中每个select子句的类型
type
表示MySQL在表中找到所需行的方式,又称“访问类型”
possible_keys
指出MySQL能使用哪个索引在表中找到行,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
key
显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL
key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度
ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
Extra
包含不适合在其他列中显示但十分重要的额外信息

(2)、profile的意义以及使用场景;
查询到 SQL 会执行多少时间, 并看出 CPU/Memory 使用量, 执行过程中 Systemlock, Table lock 花多少时间等等

30:关于InnoDB引擎的读写参数优化

(1)读取参数:
global buffer pool
local buffer
(2)写入参数:
innodb_flush_log_at_trx_commit
innodb_buffer_pool_size
(3)与IO有关单的参数:
innodb_write_io_threads = 8
innodb_read_io_threads = 8
innodb_thread_concurrency = 0
(4)缓存参数以及缓存的适用场景:
query cache/query_cache_type
并不是所有表都适合使用query cache。造成query cache失效的原因主要是相应的table发生了变更

第一个:读操作多的话看看比例,简单来说,如果是用户清单表,或者说是数据比例比较固定,比如说商品列表,是可以打开的,前提是这些库比较集中,数据库中的实务比较小。
第二个:我们“行骗”的时候,比如说我们竞标的时候压测,把query cache打开,还是能收到qps激增的效果,当然前提示前端的连接池什么的都配置一样。大部分情况下如果写入的居多,访问量并不多,那么就不要打开,例如社交网站的,10%的人产生内容,其余的90%都在消费,打开还是效果很好的,但是你如果是qq消息,或者聊天,那就很要命。
第三个:小网站或者没有高并发的无所谓,高并发下,会看到 很多 qcache 锁 等待,所以一般高并发下,不建议打开query cache

31:上线后如何监控自己的数据库的?慢日志是怎么查询的?

mysql监控工具有:zabbix,lepus。

32:你是否做过主从一致性校验?如果有,怎么做的?如果没有,你打算怎么做?

主从一致性校验有多种工具,如checksum、mysqldiff、pt-table-checksum等

33:你的数据库是否支持emoji表情?如果不支持,如何操作?

如果是utf-8字符集,需要升级至utf8-mb4便可支持emoji.

34:你如何维护数据库里面的数据字典的?

一般是直接在生产库进行注释,利用工具导出成excel方便流通。

35:表中有大字段X(例如:text类型),且字段X不会经常更新,以读为为主,请问你是选择拆成子表,还是继续放一起;为何?

拆解带来的问题:连接消耗+存储拆分空间;
不拆带来的问题:查询性能。
理由:如果能容忍拆分带来的空间问题,拆的话最好和经常要查询的表的主键在物理结构上放置在一起(分区) 顺序IO,减少连接消耗,最后这是一个文本列再加上一个全文索引来尽量抵消连接消耗。
如果能容忍不拆分带来的查询性能损失的话:上面的方案在某个极致条件下肯定会出现问题,那么不拆就是最好的选择。

36:MySQL中InnoDB引擎的行锁是通过加在什么上完成(或称实现)的?为什么是这样子的?

InnoDB是基于索引来完成行锁
例: select * from tab_with_index where id = 1 for update;
for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,
如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起。

37:如何从mysqldump产生的全库备份中只恢复某一个库、某一张表?

开放性问题:据说是腾讯的
一个6亿的表a,一个3亿的表b,通过外间tid关联,你如何最快的查询出满足条件的第50000到第50200中的这200条数据记录。
1、如果A表TID是自增长,并且是连续的,B表的ID为索引
select * from a,b where a.tid = b.id and a.tid>500000 limit 200;

2、如果A表的TID不是连续的,那么就需要使用覆盖索引.TID要么是主键,要么是辅助索引,B表ID也需要有索引。
select * from b , (select tid from a limit 50000,200) a where b.id = a .tid;

你可能感兴趣的:(MySQL,mysql,java,面试,数据库)