现在java程序员面试的话,数据库的话题是逃不掉的?面试官会问你常用什么数据库,肯定我们做业务操作的话就是mysql,那么面试官就会顺势展开下来进行追问,本篇结合我自己本身的面试经验进行一番总结,帮助大家更好的通过mysql数据库方面的面试。
问题:介绍下mysql有哪些存储引擎?适用场景等。
首先想说的是如果真是平常没这方面的研究,还真不一定能回答上来这道题,就说有哪几种可能都不知道,因为创建的时候就是点点点去创建数据库的。
第二,创建数据库的时候不涉及到存储引擎的选择,真正创建表的时候才会选择存储引擎,一般默认我们选择的是InnoDB,字符集utf8,和字符集核对:忽略大小写的utf8_general_ci,完成表创建。
回到正题存储引擎介绍:
在mysql5之后,支持的存储引擎有十几个,但是常用的就那么几种,而且默认支持的也是InnoDB,我们常用的也就是InnoDB,其他的也很少用。
功能支持 | MyISAM | Memory | InnoDB |
---|---|---|---|
存储限制 | 256TB | RAM | 64TB |
支持事务 | 否 | 否 | 是 |
支持全文索引 | 是 | 否 | 否 |
支持B树索引 | 是 | 是 | 是 |
支持哈希索引 | 否 | 是 | 否 |
支持集群索引 | 否 | 否 | 是 |
支持数据索引 | 否 | 是 | 是 |
支持数据压缩 | 是 | 否 | 否 |
空间使用率 | 地 | n/a | 高 |
支持外键 | 否 | 否 | 是 |
MyISAM:使用这个存储引擎,每个MyISAM在磁盘上存储成三个文件。
frm和MYI可以存放在不同的目录下。MYI文件用来存储索引,但仅保存记录所在页的指针,索引的结构是B+树结构。
InnoDB:InnoDB是默认的数据库存储引擎,他的主要特点有:
(1)可以通过自动增长列,方法是auto_increment。
(2)支持事务。默认的事务隔离级别为可重复度,通过MVCC(并发版本控制)来实现的。
(3)使用的锁粒度为行级锁,可以支持更高的并发;
(4)支持外键约束;外键约束其实降低了表的查询速度,但是增加了表之间的耦合度。
(5)配合一些热备工具可以支持在线热备份;
(6)在InnoDB中存在着缓冲管理,通过缓冲池,将索引和数据全部缓存起来,加快查询的速度;
(7)对于InnoDB类型的表,其数据的物理组织形式是聚簇表。所有的数据按照主键来组织。数据和索引放在一块,都位于B+数的叶子节点上;
当然InnoDB的存储表和索引也有下面两种形式:
(1)使用共享表空间存储:所有的表和索引存放在同一个表空间中。
(2)使用多表空间存储:表结构放在frm文件,数据和索引放在IBD文件中。分区表的话,每个分区对应单独的IBD文件,分区表的定义可以查看我的其他文章。使用分区表的好处在于提升查询效率。
对于InnoDB来说,最大的特点在于支持事务。但是这是以损失效率来换取的。
Memory:将数据存在内存,为了提高数据的访问速度,每一个表实际上和一个磁盘文件关联。文件是frm。
(1)支持的数据类型有限制,比如:不支持TEXT和BLOB类型,对于字符串类型的数据,只支持固定长度的行,VARCHAR会被自动存储为CHAR类型;
(2)支持的锁粒度为表级锁。所以,在访问量比较大时,表级锁会成为MEMORY存储引擎的瓶颈;
(3)由于数据是存放在内存中,一旦服务器出现故障,数据都会丢失;
(4)查询的时候,如果有用到临时表,而且临时表中有BLOB,TEXT类型的字段,那么这个临时表就会转化为MyISAM类型的表,性能会急剧降低;
(5)默认使用hash索引。
(6)如果一个内部表很大,会转化为磁盘表。
在这里只是给出3个常见的存储引擎。使用哪一种引擎需要灵活选择,一个数据库中多个表可以使用不同引擎以满足各种性能和实际需求,使用合适的存储引擎,将会提高整个数据库的性能
上面是一个大而全的存储引擎的介绍,一般面试可能不会说那么多,就讲出来
MyISAM 和 InnoDB 的主要区别:前者不支持事务,后者支持事务,前者支持全文索引,后者不支持等等。就算过。
字符集指的是一种从二进制编码到某类字符符号的映射,回影响存储的长度等。
常用的字符集我们需要了解下,utf8中文字符集,utf8mb4中文支持表情支持表情字符集,校对规则一般我们都选用utf8_general_ci、utf8mb4_general_ci忽略大小写的校验规则。
Mysql索引使用的数据结构主要有BTree索引 和 哈希索引。前者比较常用,后者不常用,适合单条记录,配置类的数据存储。
索引两个概念要了解:聚簇索引(聚集索引、主键索引)、非聚簇索引
MyISAM: B+Tree叶节点的data域存放的是数据记录的地址。而InnoDB: 其数据文件本身就是索引文件。聚集索引主键查询到最后叶子节点就是数据,非聚集索引对于InnoDB来说存在二次查询的问题。
my.cnf中配置缓存:
query_cache_type=1 query_cache_size=600000
执行命令添加缓存:
set global query_cache_type=1; set global query_cache_size=600000;
开启查询缓存后在同样的查询条件以及数据情况下,会直接在缓存中返回结果。开启查询缓存后在同样的查询条件以及数据情况下,会直接在缓存中返回结果。
通过sql命令来控制是否需要缓存;
sql_cache和sql_no_cache来控制某个查询语句是否需要缓存:
select sql_no_cache count(*) from usr;
事务的四大特性ACID是大概率会问的问题,作为开发人员也需要对事务的特性和隔离级别进行了解清除。
特性 | 说明 | 备注 |
---|---|---|
原子性(Atomicity) | 事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。 | |
一致性(Consistency) | 事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。其实一致性也是因为原子型的一种表现 | |
隔离性(Isolation) | 同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。串行化 | |
持久性(Durability) | 事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。 |
事务并发问题:
问题 | 说明 | 备注 |
---|---|---|
脏读 | 事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据,与表中最终的实际数据不一致 | |
不可重复读 | 事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。读取结果与上次结果不一致 | |
幻读 | 系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。修改过来了但又被改了,导致结果和预期不一样 |
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
MyISAM中采用的是表级锁,特定为:Mysql中锁定 粒度最大 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
InnoDB存储引擎采用的是行级锁,特点是:Mysql中锁定 粒度最小的一种锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,有可能出现死锁。
方案 | 说明 | 备注 |
---|---|---|
限定数据范围 | 带上查询条件减少数据量 | 近一个月的订单查询等 |
读/写分离 | 经典的方案,主库负责写,读库负责度 | 能够提高数据库的并发能力 |
缓存 | 缓存可以在一些场景中提高效率 | 对重量级、更新少的数据可以考虑使用应用级别的缓存; |
垂直分区 | 把一张表拆成多张表存储 | 用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库,特点是行数据变少,这个应该根据实际业务场景配合水平分区去做选择 |
水平分区 | 把一张大表tb拆成tb1、tb2、tb3 | 使用中间件mycat或者sharding-jdbc进行分片拆分表达到扩容的目的,比较的常用,但是拆分后会带来逻辑、部署、运维等复杂度 |
mysql面试的话可以聊的话题很多,上面罗列的是比较重要的一些,不是全部,比方说走索引的效率为log2(N),不走索引的效率是N等等,再比如常见的分页问题,第一页查询和后面的页数大的查询速率的问题是一样还是不一样这些问题,还需要大家面试前多进行一些总结,总结成自己的套路,去让面试官认为你很专业,好学,不一定你讲出来的全部都对,但是一定要给面试官留的印象是你很懂。欢迎关注我的公众号:Java时间屋 进行交流。