目录
1、数据库的三范式是什么
2、MySQL数据库引擎有哪些
3、说说InnoDB与MyISAM的区别
4、数据库的事务
5、索引是什么
6、SQL优化手段有哪些
7、简单说一说drop、delete与truncate的区别
8、什么是视图
9、 什么是内联接、左外联接、右外联接?
10、并发事务带来哪些问题?
11,事务隔离级别有哪些?MySQL的默认隔离级别是?
12,大表如何优化?
13、分库分表之后,id 主键如何处理?
14、 说说在 MySQL 中一条查询 SQL 是如何执行的?
15、索引有什么优缺点?
16、 MySQL 中 varchar 与 char 的区别?varchar(30) 中的 30代表的涵义?
17、 int(11) 中的 11 代表什么涵义?
18、 为什么 SELECT COUNT(*) FROM table 在 InnoDB 比MyISAM 慢?
说说 InnoDB 与 MyISAM 有什么区别?
20、MySQL 索引类型有哪些?
21、什么时候不要使用索引?
22、说说什么是 MVCC?
23、MVCC 可以为数据库解决什么问题?
24、说说 MVCC 的实现原理
25、MySQL 事务隔离级别?
26、 请说说 MySQL 数据库的锁?
27、说说什么是锁升级?
28、说说悲观锁和乐观锁
29、怎样尽量避免死锁的出现?
30、使用 MySQL 的索引应该注意些什么?
31、CHAR 和 VARCHAR 的区别?
32、主键和候选键有什么区别?
33、主键与索引有什么区别?
34、 MySQL 如何做到高可用方案?
第一范式:列不可再分
第二范式:行可以唯一区分,主键约束
第三范式:表的非主属性不能依赖与其他表的非主属性 外键约束
且三大范式是一级一级依赖的,第二范式建立在第一范式上,第三范式建立第一第二范式上。
如何查看mysql提供的所有存储引擎
mysql> show engines;
mysql常用引擎包括:MYISAM、Innodb、Memory、MERGE
什么是事务?:
多条sql语句,要么全部成功,要么全部失败。
事务的特性:
数据库事务特性:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durabiliy)。简称ACID。
原子性:组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有操作都成功, 整个事务才会提交。任何一个操作失败,已经执行的任何操作都必须撤销,让数据库返回初始 状态。
一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的。即数据不会被破坏。 如A转账100元给B,不管操作是否成功,A和B的账户总额是不变的。
隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对彼此产生干 扰
持久性:一旦事务提交成功,事务中的所有操作都必须持久化到数据库中。
官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中 的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。我们通常所说的索引,包括聚集索引、覆盖索引、组合索引、前缀索引、唯一索引等,没有特 别说明,默认都是使用B+树结构组织(多路搜索树,并不一定是二叉的)的索引。
1、查询语句中不要使用select *
2、尽量减少子查询,使用关联查询(left join,right join,inner join)替代
3、减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代
4、or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好)
5、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
6、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
SQL中的drop、delete、truncate都表示删除,但是三者有一些差别
delete和truncate只删除表的数据不删除表的结构 速度,一般来说: drop> truncate >delete delete 语句是dml,这个操作会放到rollback segement中,事务提交之后才生效; 如果有相应的trigger,执行的时候将被触发. truncate,drop是ddl, 操作立即生效,原数据不放到rollback segment中,不能回滚. 操作不触发trigger.
视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,试图通常是 有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易, 相比多表查询。
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对 同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
不可重复读和幻读区别:
不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增 或者删除比如多次读取一条记录发现记录增多或减少了。
SQL 标准定义了四个隔离级别:
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通SELECT @@tx_isolation;命令来查看
mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+
这里需要注意的是:与 SQL 标准不同的地方在于 InnoDB 存储引擎在 REPEATABLE-READ(可重读) 事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server) 是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-
READ(可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串行化) 隔离级别。因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是
READ-COMMITTED(读取提交内容) ,但是你要知道的是InnoDB 存储引擎默认使用
REPEAaTABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下一般会用到 SERIALIZABLE(可串行化) 隔离级别。
当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
限定数据的范围
务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们 可以控制在一个月的范围内;
读/写分离
经典的数据库拆分方案,主库负责写,从库负责读;
垂直分区
根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 如下图所示,这样来说大家应该就更容易理解了。
水平分区
保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达 到了分布式的目的。 水平拆分可以支撑非常大的数据量。
水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据 拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单 一表数据量过大对性能造成影响。
水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库 。
水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨节点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
下面补充一下数据库分片的两种常见方案:
客户端代理: 分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。 当当网的 Sharding-JDBC 、阿里的TDDL是两种比较常用的实现。
中间件代理: 在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。 我们现在谈的 Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现。
详细内容可以参考: MySQL大表优化方案: https://segmentfault.com/a/1190000006158186
因为要是分成多个表之后,每个表都是从 1 开始累加,这样是不对的,我们需要一个全局唯一的 id来支持。
生成全局 id 有下面这几种方式:
UUID:不适合作为主键,因为太长了,并且无序不可读,查询效率低。比较适合用于生成唯 一的名字的标示比如文件的名字。
数据库自增 id : 两台数据库分别设置不同步长,生成不重复ID的策略来实现高可用。这种方式生成的 id 有序,但是需要独立部署数据库实例,成本高,还会有性能瓶颈。
利用 redis 生成 id : 性能比较好,灵活方便,不依赖于数据库。但是,引入了新的组件造成系统更加复杂,可用性降低,编码更加复杂,增加了系统成本。
Twitter的snowflake算法 :Github 地址:https://github.com/twitter-archive/snowflake。美团的Leaf分布式ID生成系统 :Leaf 是美团开源的分布式ID生成器,能保证全局唯一性、趋势递增、单调递增、信息安全,里面也提到了几种分布式方案的对比,但也需要依赖关系数据 库、Zookeeper等中间件。感觉还不错。美团技术团队的一篇文章:https://tech.meituan.co m/2017/04/21/mt-leaf.html 。
varchar 与 char 的区别,char 是一种固定长度的类型,varchar 则是一种可变长度的类型。
varchar(30) 中 30 的涵义最多存放 30 个字符。varchar(30) 和 (130) 存储 hello 所占空间一样,但后者在排序时会消耗更多内存,因为 ORDER BY col 采用 fixed_length 计算 col 长度(memory 引擎也一样)。
对效率要求高用 char,对空间使用要求高用 varchar。
int(11) 中的 11,不影响字段存储的范围,只影响展示效果。
对于 SELECT COUNT(*) FROM table 语句,在没有 WHERE 条件的情况下,InnoDB 比 MyISAM 可能会慢很多,尤其在大表的情况下。因为,InnoDB 是去实时统计结果,会全表扫描;而 MyISAM 内部维持了一个计数器,预存了结果,所以直接返回即可。
建议:一般情况下,个人建议优先选择 InnoDB 存储引擎,并且尽量不要将 InnoDB 与 MyISAM 混合使用。
主键索引
索引列中的值必须是唯一的,不允许有空值。
普通索引
MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值。
唯一索引
索引列中的值必须是唯一的,但是允许为空值。
全文索引
只能在文本类型CHAR,VARCHAR,TEXT类型字段上创建全文索引。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引。MyISAM和InnoDB中都可以 使用全文索引。
空间索引
MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。
前缀索引
在文本类型如CHAR,VARCHAR,TEXT类列上创建索引时,可以指定索引列的长度,但是数值类型不能指定。
其他(按照索引列数量分类)
组合索引的使用,需要遵循最左前缀匹配原则(最左匹配原则)。一般情况下在条件允许的情 况下使用组合索引替代多个单列索引使用。
多版本并发控制(MVCC=Multi-Version Concurrency Control),是一种用来解决读 - 写冲突的无锁并发控制。也就是为事务分配单向增长的时间戳,为每个修改保存一个版本。版本与事务时间戳 关联,读操作只读该事务开始前的数据库的快照(复制了一份数据)。这样在读操作不用阻塞写操 作,写操作不用阻塞读操作的同时,避免了脏读和不可重复读。
在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数 据库并发读写的性能。同时还可以解决脏读、幻读、不可重复读等事务隔离问题,但不能解决更新 丢失问题。
MVCC 的目的就是多版本并发控制,在数据库中的实现,就是为了解决读写冲突,它的实现原理主要是依赖记录中的 3 个隐式字段、undo 日志、Read View 来实现的。
关于 MySQL 的锁机制,可能会问很多问题,不过这也得看面试官在这方面的知识储备。
MySQL 中有共享锁和排它锁,也就是读锁和写锁。
MySQL 行锁只能加在索引上,如果操作不走索引,就会升级为表锁。因为 InnoDB 的行锁是加在索引上的,如果不走索引,自然就没法使用行锁了,原因是 InnoDB 是将 primary key index 和相关的行数据共同放在 B+ 树的叶节点。InnoDB 一定会有一个 primary key,secondary index 查找的时候,也是通过找到对应的 primary,再找对应的数据行。
当非唯一索引上记录数超过一定数量时,行锁也会升级为表锁。测试发现当非唯一索引相同的 内容不少于整个表记录的二分之一时会升级为表锁。因为当非唯一索引相同的内容达到整个记 录的二分之一时,索引需要的性能比全文检索还要大,查询语句优化时会选择不走索引,造成 索引失效,行锁自然就会升级为表锁。
悲观锁
说的是数据库被外界(包括本系统当前的其他事物以及来自外部系统的事务处理)修改保持着保守 态度,因此在整个数据修改过程中,将数据处于锁状态。悲观的实现往往是依靠数据库提供的锁机 制,也只有数据库层面提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统汇总实 现了加锁机制,也是没有办法保证系统不会修改数据。
在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定读。读取数据时给加锁,其它事务 无法修改这些数据。修改删除数据时也要加锁,其它事务无法读取这些数据。
乐观锁
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机 制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事 务而言,这样的开销往往无法承受。
而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实 现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过 为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对 此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果 提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
CHAR 和VARCHAR 类型在存储和检索方面有所不同
CHAR 列长度固定为创建表时声明的长度,长度值范围是1 到255当 CHAR 值被存储时,它们被用空格填充到特定长度,检索CHAR 值时需删除尾随空格。
表格的每一行都由主键唯一标识,一个表只有一个主键。主键也是候选键。按照惯例,候选键可以被 指定为主键,并且可以用于任何外 键引用。
主键一定会创建一个唯一索引,但是有唯一索引的列不一定是主键; 主键不允许为空值,唯一索引列允许空值;
一个表只能有一个主键,但是可以有多个唯一索引; 主键可以被其他表引用为外键,唯一索引列不可以;
主键是一种约束,而唯一索引是一种索引,是表的冗余数据结构,两者有本
MySQL 高可用,意味着不能一台 MySQL 出了问题,就不能访问了。