关于MySQL的知识点与面试常见问题都在这里

我本身总结的Java学习的一些知识点以及面试问题,目前已经开源,会一直完善下去,欢迎建议和指导欢迎Star: github.com/Snailclimb/…html

书籍推荐

《高性能MySQL : 第3版》mysql

文字教程推荐

MySQL 教程(菜鸟教程)git

MySQL教程(易百教程)github

视频教程推荐

基础入门: 与MySQL的零距离接触-慕课网面试

Mysql开发技巧: MySQL开发技巧(一)  MySQL开发技巧(二)  MySQL开发技巧(三)算法

Mysql5.7新特性及相关优化技巧: MySQL5.7版本新特性  性能优化之MySQL优化sql

MySQL集群(PXC)入门  MyCAT入门及应用数据库

常见问题总结

  • ①存储引擎

    MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇segmentfault

  • ②字符集及校对规则

    字符集指的是一种从二进制编码到某类字符符号的映射。校对规则则是指某种字符集下的排序规则。Mysql中每一种字符集都会对应一系列的校对规则。缓存

    Mysql采用的是相似继承的方式指定字符集的默认值,每一个数据库以及每张数据表都有本身的默认值,他们逐层继承。好比:某个库中全部表的默认字符集将是该数据库所指定的字符集(这些表在没有指定字符集的状况下,才会采用默认字符集) PS:整理自《Java工程师修炼之道》

    详细内容能够参考: MySQL字符集及校对规则的理解

  • ③索引相关的内容(数据库使用中很是关键的技术,合理正确的使用索引能够大大提升数据库的查询性能)

      Mysql索引使用的数据结构主要有BTree索引哈希索引 。对于哈希索引来讲,底层的数据结构就是哈希表,所以在绝大多数需求为单条记录查询的时候,能够选择哈希索引,查询性能最快;其他大部分场景,建议选择BTree索引。

      Mysql的BTree索引使用的是B数中的B+Tree,但对于主要的两种存储引擎的实现方式是不一样的。

      MyISAM: B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,则取出其data域的值,而后以data域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。

      InnoDB: 其数据文件自己就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件自己就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,所以InnoDB表数据文件自己就是主索引。这被称为“聚簇索引(或汇集索引)”。而其他的索引都做为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不一样的地方。在根据主索引搜索时,直接找到key所在的节点便可取出数据;在根据辅助索引查找时,则须要先取出主键的值,在走一遍主索引。 所以,在设计表的时候,不建议使用过长的字段做为主键,也不建议使用非单调的字段做为主键,这样会形成主索引频繁分裂。 PS:整理自《Java工程师修炼之道》

    详细内容能够参考:

    干货:mysql索引的数据结构

    MySQL优化系列(三)--索引的使用、原理和设计优化

  • ④查询缓存的使用

    my.cnf加入如下配置,重启Mysql开启查询缓存

    query_cache_type=1
    query_cache_size=600000
    复制代码

    Mysql执行如下命令也能够开启查询缓存

    set global  query_cache_type=1;
    set global  query_cache_size=600000;
    复制代码

    如上,开启查询缓存后在一样的查询条件以及数据状况下,会直接在缓存中返回结果。这里的查询条件包括查询自己、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息。所以任何两个查询在任何字符上的不一样都会致使缓存不命中。此外,若是查询中包含任何用户自定义函数、存储函数、用户变量、临时表、Mysql库中的系统表,其查询结果也不会被缓存。

    缓存创建以后,Mysql的查询缓存系统会跟踪查询中涉及的每张表,若是这些表(数据或结构)发生变化,那么和这张表相关的全部缓存数据都将失效。

    缓存虽然可以提高数据库的查询性能,可是缓存同时也带来了额外的开销,每次查询后都要作一次缓存操做,失效后还要销毁。 所以,开启缓存查询要谨慎,尤为对于写密集的应用来讲更是如此。若是开启,要注意合理控制缓存空间大小,通常来讲其大小设置为几十MB比较合适。此外,还能够经过sql_cache和sql_no_cache来控制某个查询语句是否须要缓存:

    select sql_no_cache count(*) from usr;
    复制代码
  • ⑤事务机制

    关系性数据库须要遵循ACID规则,具体内容以下:

事务的特性

  1. 原子性: 事务是最小的执行单位,不容许分割。事务的原子性确保动做要么所有完成,要么彻底不起做用;
  2. 一致性: 执行事务先后,数据保持一致;
  3. 隔离性: 并发访问数据库时,一个用户的事物不被其余事物所干扰,各并发事务之间数据库是独立的;
  4. 持久性: 一个事务被提交以后。它对数据库中数据的改变是持久的,即便数据库 发生故障也不该该对其有任何影响。

为了达到上述事务特性,数据库定义了几种不一样的事务隔离级别:

  • READ_UNCOMMITTED(未受权读取): 最低的隔离级别,容许读取还没有提交的数据变动,可能会致使脏读、幻读或不可重复读

  • READ_COMMITTED(受权读取): 容许读取并发事务已经提交的数据,能够阻止脏读,可是幻读或不可重复读仍有可能发生

  • REPEATABLE_READ(可重复读): 对同一字段的屡次读取结果都是一致的,除非数据是被自己事务本身所修改,能够阻止脏读和不可重复读,但幻读仍有可能发生。

  • SERIALIZABLE(串行): 最高的隔离级别,彻底服从ACID的隔离级别。全部的事务依次逐个执行,这样事务之间就彻底不可能产生干扰,也就是说,该级别能够防止脏读、不可重复读以及幻读。可是这将严重影响程序的性能。一般状况下也不会用到该级别。

    这里须要注意的是:Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.

    事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),经过保存修改的旧版本信息来支持并发一致性读和回滚等特性。

    详细内容能够参考: 多是最漂亮的Spring事务管理详解

  • ⑥锁机制与InnoDB锁算法

    MyISAM和InnoDB存储引擎使用的锁:

    • MyISAM采用表级锁(table-level locking)。
    • InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

    表级锁和行级锁对比:

    • 表级锁: Mysql中锁定 粒度最大 的一种锁,对当前操做的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的几率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
    • 行级锁: Mysql中锁定 粒度最小 的一种锁,只针对当前操做的行进行加锁。 行级锁能大大减小数据库操做的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。

    详细内容能够参考: Mysql锁机制简单了解一下

    InnoDB存储引擎的锁的算法有三种:

    • Record lock:单个行记录上的锁
    • Gap lock:间隙锁,锁定一个范围,不包括记录自己
    • Next-key lock:record+gap 锁定一个范围,包含记录自己

    相关知识点:

    1. innodb对于行的查询使用next-key lock
    2. Next-locking keying为了解决Phantom Problem幻读问题
    3. 当查询的索引含有惟一属性时,将next-key lock降级为record key
    4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会致使幻读问题的产生
    5. 有两种方式显式关闭gap锁:(除了外键约束和惟一性检查外,其他状况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1
  • ⑦大表优化

    当MySQL单表记录数过大时,数据库的CRUD性能会明显降低,一些常见的优化措施以下:

  1. 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。好比:咱们当用户在查询订单历史的时候,咱们能够控制在一个月的范围内。;

  2. 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;

  3. 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据能够考虑使用应用级别的缓存;

  4. 垂直分区:

    根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登陆信息又有用户的基本信息,能够将用户表拆分红两个单独的表,甚至放到单独的库作分库。

    简单来讲垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 以下图所示,这样来讲你们应该就更容易理解了。

    垂直拆分的优势: 可使得行数据变小,在查询时减小读取的Block数,减小I/O次数。此外,垂直分区能够简化表的结构,易于维护。

    垂直拆分的缺点: 主键会出现冗余,须要管理冗余列,并会引发Join操做,能够经过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;

  5. 水平分区:

    保持数据表结构不变,经过某种策略存储数据分片。这样每一片数据分散到不一样的表或者库中,达到了分布式的目的。 水平拆分能够支撑很是大的数据量。

    水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时能够把一张的表的数据拆成多张表来存放。举个例子:咱们能够将用户信息表拆分红多个用户信息表,这样就能够避免单一表数据量过大对性能形成影响。

    数据库水平拆分

    水品拆分能够支持很是大的数据量。须要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但因为表的数据仍是在同一台机器上,其实对于提高MySQL并发能力没有什么意义,因此 水品拆分最好分库

    水平拆分可以 支持很是大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨界点Join性能较差,逻辑复杂。《Java工程师修炼之道》的做者推荐 尽可能不要对数据进行分片,由于拆分会带来逻辑、部署、运维的各类复杂度 ,通常的数据表在优化得当的状况下支撑千万如下的数据量是没有太大问题的。若是实在要分片,尽可能选择客户端分片架构,这样能够减小一次和中间件的网络I/O。

    下面补充一下数据库分片的两种常见方案:

    • 客户端代理: 分片逻辑在应用端,封装在jar包中,经过修改或者封装JDBC层来实现。 当当网的 Sharding-JDBC 、阿里的TDDL是两种比较经常使用的实现。
    • 中间件代理: 在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。 咱们如今谈的 Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现。

详细内容能够参考: MySQL大表优化方案

欢迎关注个人微信公众号:"Java面试通关手册"(一个有温度的微信公众号,无广告,单纯技术分享,期待与你共同进步~~~坚持原创,分享美文,分享各类Java学习资源。你想关注便关注,公众号只是我记录文字和生活的地方,无所谓利益。)

个人公众号
相关文章
相关标签/搜索