MySQL关系数据库
1、什么是MySQL
- MySQL是一个关系型数据库管理系统,开源免费的,并且方便扩展。
2、数据库三大范式是什么
-
第一范式:每个列都不可以再拆分;
-
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分;
-
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键;
在设计数据库表结构的时候,要尽量遵守三大范式,事实上我们经常会为了性能而妥协数据库的设计;
3、SQL查询的基本原理
-
单表查询:根据WHERE条件过滤表中的记录,形成中间表(中间表对用户不可见),然后根据SELECT的选择列选择相应的列进行返回最终结果。
-
两表连接查询:对两表求笛卡尔积并用ON条件和连接类型进行过滤形成中间表;然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果。
-
多表连接查询:先对第一个和第二个表按照两表连接做查询,然后用查询结果和第三个表做连接查询,以此类推,直到所有的表都连接上为止,最终形成一个中间的结果表,然后根据WHERE条件过滤中间表的记录,并根据SELECT指定的列返回查询结果;
4、MySQL的框架有几个组件, 各是什么作用
-
MySQL 可以分为 Server 层和存储引擎层两部分;
-
Server 层涵盖 MySQL 的大多数核心服务功能,比如存储过程、触发器、视图等;
-
而存储引擎层负责数据的存储和提取;
5、SQL执行流程,SQL的生命周期
-
连接器
客户端与数据库server层的连接器进行连接; -
查询缓存
连接建立完成后,会判断查询缓存是否开启,如果已经开启,会判断sql是select还是update/insert/delete,对于select,尝试去查询缓存,如果命中缓存直接返回数据给客户端, 如果缓存没有命中,或者没有开启会进入到下一步分析器; -
分析器
分析器进行词法分析和语法分析,校验数据库表和字段是否存在,判断SQL是否满足MySQL语法; -
优化器
优化器对sql执行计划分析,得到最终执行计划,得到优化后的执行计划交给执行器。优化器是在表里面有多个索引的时候,决定使用哪个索引,或者在一个语句有多表关联的时候,决定各个表的连接顺序; -
执行器
判断有没有执行查询的权限,如果没有就返回没有权限的错误,如果有,执行器调用存储引擎执行sql得到响应结果返回结果客户端,如果缓存开启的, 更新缓存;
6、SQL的几种连接(join)查询方式
-
内连接(inner join)
查出的是两张表的交集,两张表都有的才查出来; -
外连接
左外连接(left join)以左表为主表(查询全部), 右表为辅表(没有的显示null);
右外连接(right join)刚好相反; -
全连接(full join)
两个表的所有数据都展示出来; -
联合查询
union:不合并;
union all:合并相同项;
7、如何获取当前数据库版本
- 使用 select version() 获取;
8、char 和 varchar 的区别是什么
-
char(n) :固定长度类型;
-
varchar(n) :可变长度;
-
从空间上考虑 varcahr 比较合适;从效率上考虑 char 比较合适;
9、float 和 double 的区别是什么
- float 最多可以存储 8 位的十进制数,并在内存中占 4 字节;
- double 最可可以存储 16 位的十进制数,并在内存中占 8 字节;
10、MySQL存储引擎以及区别
-
Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
-
myisam引擎(默认引擎):不提供事务的支持,也不支持行级锁和外键。
-
memory引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。
11、什么是索引
索引是一种数据结构,是数据库管理系统中一个排序的数据结构,以协助快速查询数据库表中数据。索引的实现通常使用B+树或hash表;
12、索引有哪些优缺点
优点
-
可以大大加快数据的检索速度;
-
通过使用索引,可以在查询的过程中,使用优化器提高性能;
缺点
-
时间方面:当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护;
-
空间方面:索引需要占物理空间。
13、索引有哪几种类型
-
主键索引:数据列不允许重复,不允许为NULL,一个表只能有一个主键。
-
唯一索引:数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
ALTER TABLE table_name ADD UNIQUE (column)
- 普通索引:基本的索引类型,没有唯一性的限制,允许为NULL值,一个表允许多个列创建普通索引。
ALTER TABLE table_name ADD INDEX index_name (column)
- 全文索引:是目前搜索引擎使用的一种关键技术,MyISAM存储引擎才有全文索引。
ALTER TABLE table_name ADD FULLTEXT (column)
14、索引的数据结构
-
B+树
B树索引是MySQL数据库中使用最频繁的索引类型; -
哈希索引
15、数据库为什么使用B+树而不是B树
- B树只适合随机检索,而B+树同时支持随机检索和顺序检索;
16、索引算法有哪些
-
BTree算法
mysql默认的算法。因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量; -
Hash算法
只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到叶子节点这样多次IO访问,所以检索效率远高于BTree索引;
17、创建索引的原则?索引设计的原则
索引虽好,但也不是无限制的使用,最好符合以下几个原则
-
为常作为查询条件的字段建立索引,where子句中的列,或者连接子句中指定的列
-
为经常需要排序、分组操作的字段建立索引
-
更新频繁字段不适合创建索引
-
不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
18、什么情况使用了索引,查询还是慢
-
索引全表扫描
-
索引过滤性不好
-
频繁回表的开销
19、什么是聚簇索引?何时使用聚簇索引与非聚簇索引
-
聚簇索引:将数据与索引放到了一块,索引结构的叶子节点存储了行数据,找到索引也就找到了数据;
-
非聚簇索引:将数据与索引分开存储,索引结构的叶子节点存储的是行数据的地址;
-
聚簇索引数据访问更快。需要取出一定范围内的数据时,用聚簇索引也比用非聚簇索引好;
20、联合(组合)索引是什么
- MySQL可以使用多个字段组合建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引;
21、怎么验证 mysql 的索引是否满足需求
- 使用 explain 查看 SQL 是如何执行查询语句的,从而分析索引是否满足需求;
- explain 语法:explain select * from table where type=1;
22、MySQL使用自增主键的好处
-
自增主键按顺序存放,增删数据速度快,对于检索非常有利;
-
数字型,占用空间小,易排序;
-
使用整形才可以使用AUTO_INCREAMENT;
23、 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是多少
- 表类型如果是 MyISAM ,那 id 就是 8;
- 表类型如果是 InnoDB,那 id 就是 6;
InnoDB 表只会把自增主键的最大 id 记录在内存中,所以重启之后会导致最大 id 丢失。
24、什么是最左前缀原则?什么是最左匹配原则
- 最左前缀原则,就是最左边的优先;
- 指的是联合索引中,优先走最左边列的索引;
25、什么是数据库事务
- 事务是逻辑上的一组操作,要么都执行,要么都不执行;
26、事务的四大特性(ACID)
- 原子性:要么全成功,要么不成功;(张三减去三百,李四加三百,要么都成功,要么都不成功)
- 一致性:事务执行后,数据库状态与其他业务数据保持一致;(转账前后金额总和不变)
- 隔离性:并发操作中不同事务之间应该隔离开来,不会互相干扰;
- 持久性:事务提交后,数据必须持久化到数据库中即使数据库奔溃,重启后也能通过某种机制恢复;
27、什么是并发事务问题
- 脏读:读到另一个事务未提交数据;
- 不可重复度:对同一记录两次读取结果不一致,另一事务做了修改;
- 幻读:对同一张表两次查询不一致,因为另一事务插入一条记录;
28、MySQL数据库可重复读隔离级别是怎么实现的
- MySQL可重复读是通过并发版本控制MVCC实现的;
29、对MySQL的锁了解吗
- 当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。
30、什么是事务的隔离级别
- 串行化:不会出现并发问题,非并发访问,性能最差,容易死锁;
- 可重复读:防止脏读和不可重复读,性能第三(幻读无法处理);–mysql默认级别
- 读已提交数据:防止脏读,性能第二;–oracle默认级别
- 读未提交数据:可能出现事务并发问题,隔离级别最差,性能第一;
31、隔离级别与锁的关系
-
在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突;
-
在Read Committed级别下,读操作需要加共享锁,在语句执行完以后释放共享锁;
-
在Repeatable Read级别下,读操作需要加共享锁,事务执行完毕后才释放共享锁;
-
在SERIALIZABLE级别下,是限制性最强的隔离级别,该级别下锁定整个范围的键,并一直持有锁,直到事务完成;
32、共享锁和排他锁的区别
-
共享锁是读取操作创建的锁,防止数据在被读取的时候被别的线程加上写锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改,直到已释放所有共享锁
使用方式:在需要执行的语句后面加上 for update就可以了; -
排他锁 简称X锁。若事务T对数据A加上排他锁,则只允许事务T读取和修改数据A,其他任何事务都不能再对A加任何类型的锁,直到事务T释放X锁;
33、数据库的乐观锁和悲观锁是什么?怎么实现的
- 乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。实现方式:乐观锁一般会使用版本号机制或CAS算法实现;
- 悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放。实现方式:使用数据库中的锁机制;
34、如何定位及优化SQL语句的性能问题?创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因
- 对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了explain命令来查看语句的执行计划;
- 不管是哪种数据库,在对一条SQL语句进行执行的过程中都会做很多相关的优化,对于查询语句,最重要的优化方式就是使用索引;
- 执行计划,就是显示数据库引擎对于SQL语句执行的详细情况;
35、mysql 问题排查都有哪些手段
- 使用 show processlist 命令查看当前所有连接信息;
- 使用 explain 命令查询 SQL 语句执行计划;
- 开启慢查询日志,查看慢查询的 SQL;
36、如何做 mysql 的性能优化
为搜索字段创建索引。
避免使用 select *,列出需要查询的字段。
垂直分割分表。
选择正确的存储引擎。
37、常用SQL查询语句优化方法
-
不要使用select * from t,用具体的字段列表代替“*”,使用星号会降低查询效率;
-
应尽量避免在where子句中使用!=或<>操作符,避免在where子句中字段进行null值判断;
-
避免使用左模糊,左模糊查询将导致全表扫描;
-
IN语句查询时包含的值不应过多,否则将导致全表扫描;
-
为经常作为查询条件的字段,经常需要排序、分组操作的字段建立索引;
-
尽量用union all代替union,union需要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的CPU运算,加大资源消耗;
38、数据库结构优化
- 字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表;
- *对于需要经常联合查询的表,可以建立中间表以提高查询效率;
- 设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,但是,合理的加入冗余字段可以提高查询速度。
39、大表怎么优化?千万数据CRUD比较慢,如何优化
-
限定数据的查询范围: 务必禁止不带任何限制数据范围条件的查询语句;
-
读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
-
缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;
40、分库分表是怎么做的
分库分表主要有垂直分表和水平分表
-
垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表;
-
水平分表 保持数据表结构不变,通过某种策略进行存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。水平拆分可以支撑非常大的数据量。
尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度
41、大批量数据删除,怎么一次删除100万条数据
- 删除数据的速度和创建的索引数量是成正比的, 在删除数据之前删除索引删除完成后重新创建索引;
- 选择不需要删除的数据,并把它们存在一张空表,删掉原始表,新表命名为原始表名;
- 分批删除,在一个连接中循环执行 20 次 delete from T limit 500,删除一个表里面的前 10000 行数据(优先考虑);
42、MySQL大数据量分页查询方法及其优化
- 使用覆盖索引:如果一条SQL语句,通过索引可以直接获取查询的结果,不再需要回表查询,就称这个索引为覆盖索引;
- 子查询优化,通过把分页的SQL语句改写成子查询的方法获得性能上的提升。
43、delete和truncate区别
- delete删除可以配合where条件选择性删除数据,truncate删除表全部数据;
- delete删除之后可回滚,truncate不可回滚;
- delete删除后不影响表所占用的extent,高水线位置不变,truncate释放空间,重置高水线和所有索引;
Redis非关系数据库
44、redis 是什么
- Redis是一个开源的Key-Value存储的数据结构,数据是存在内存中的,读写速度非常快。可以用作缓存、菲关系型数据库、消息中间件等,并提供多种语言的API。
45、Redis有哪些数据类型
Redis主要有5种数据类型。
- string:字符串、整数或者浮点数(stringRedisTemplate.posForValue)
- list:列表(stringRedisTemplate.posForList)
- hash:包含键值对的无序散列表(stringRedisTemplate.posForHash)
- set:无序集合(stringRedisTemplate.posForSet)
- zset:有序集合(stringRedisTemplate.posForZSet)
46、Redis的应用场景(哪些功能)
- 计数器:Redis 读写性能非常高,很适合存储频繁读写的计数量;
- 缓存:将热点数据放到内存中,设置内存最大使用量及淘汰策略保证缓存命中率;
- 消息队列:List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息;
- 分布式锁实现:可以使用 Redis 自带的 SETNX 命令实现分布式锁;
47、Redis有哪些优缺点(为什么要用 Redis /为什么要用缓存)
优点
- 读写性能优异;
- 数据结构丰富,支持数据持久化;
- 支持主从复制,可以进行读写分离;
- 支持事务,Redis的所有操作都是原子性的;
缺点
- 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写;
- Redis 不具备自动容错和恢复功能,主机从机的宕机需要手动恢复;
48、Redis为什么这么快
- 完全基于内存,绝大部分请求是纯粹的内存操作;
- 数据结构简单;
- 用单线程,避免了不上下文切换和竞争,也不存在多进程,不用去考虑各种锁的问题;
49、redis 支持的 java 客户端都有哪些
- Redisson、Jedis、lettuce等等,官方推荐使用Redisson。
50、 jedis 和 redisson 有哪些区别
- Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;
- Redisson实现了分布式和可扩展的Java数据结构,功能简单,不支持字符串操作,排序、事务、管道、分区等Redis特性;
51、redis 常见的性能问题有哪些?该如何解决
- 主服务器写内存快照,会阻塞主线程的工作;
- 为了主从复制的速度和连接的稳定性,主从库最好在同一个局域网内;
52、怎么保证缓存和数据库数据的一致性
- 合理设置缓存的过期时间;
- 数据库操作时同步更新 Redis,可以使用事物机制来保证数据的一致性;
53、redis 如何做内存优化
- 尽可能使用散列表(hashes),散列表使用的内存非常小;
54、什么是Redis持久化
- 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
55、Redis 的持久化机制是什么?各自的优缺点(如何选择合适的持久化方式)
- 快照:RDB是Redis默认的持久化方式。按照一定的时间间隔将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件dump.rdb,如果持久化之间 redis 发生故障,会发生数据丢失;
- AOF: 将Redis执行的每条写命令记录到单独的aof日志文件中,当重启Redis服务时,从日志文件中恢复数据;
当两种方式同时开启时,数据恢复时,Redis会优先选择AOF恢复。
56、Redis的过期键的删除策略
- Redis可以设置Redis中缓存key的过期时间。Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理。
过期策略通常有以下三种:
-
定时过期:每个设置过期时间的key都创建一个定时器,到过期时间就会立即清除。但是会占用大量的CPU资源,影响性能。
-
惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存;
-
定期过期:每隔一段时间,删除里面过期的key。可以使得CPU和内存资源达到最优的平衡效果。
Redis中同时使用了惰性过期和定期过期两种过期策略。
57、Redis的内存淘汰策略有哪些
- 淘汰策略是指在Redis服务器用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
全局的键空间选择性移除
-
allkeys-lru(常用):移除最近最少使用的key。
-
allkeys-random:随机移除某个key。
-
noeviction:新写入操作会报错。
设置过期时间的键空间选择性移除
-
volatile-lru(常用):移除最近最少使用的key。
-
volatile-random:随机移除某个key。
-
volatile-ttl:有更早过期时间的key优先移除。
58、Redis事务
- Redis 事务不保证原子性,且没有回滚,中间某条命令执行失败,前面已执行的命令不回滚,后续的指令继续执行。
59、redis为什么不支持回滚
- 鉴于没有任何机制能100%避免错误,为了更简单、更快速的来处理事务, 所以 Redis 选择了无回滚。
60、Redis事务的三个阶段
- 事务开始 MULTI;
- 命令入队;
- 事务执行 EXEC;
61、Redis事务命令
- ATCH:该命令是一个乐观锁,可以监控一个或多个键,一旦其中有一个键被修改,之后的事务就不会执行,监控一直持续到EXEC命令;
- UNWATCH:可以取消watch对所有key的监控;
- MULTI:用于开启一个事务。MULTI执行之后,客户端可发送的命令被放到一个队列中,当EXEC命令被调用时,才会被执行;
- EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值;
- DISCARD:通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务;
62、哨兵模式
sentinel哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:
-
集群监控:负责监控 redis master 和 slave 进程是否正常工作;
-
消息通知:如果某个实例有故障,发送消息通知给管理员;
-
故障转移:如果 master node 挂掉了,会自动转移到 slave node 上;
-
配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址;
哨兵至少需要 3 个实例,来保证自己的健壮性。
哨兵 + redis 主从的部署架构,不保证数据零丢失,只保证高可用。
63、生产环境中的 redis 是怎么部署的
- 一半机器部署 redis 主实例,另外 一半部署 redis 的从实例,每个主实例挂了一个从实例,一半机器对外提供读写服务;
- 每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移
- 32G 内存机器分配给redis 的内存尽量不要超过 10g;
64、Redis实现分布式锁
- Redis为单线程模式串行访问,多客户端对Redis的连接不存在竞争关系,Redis中可以使用SETNX命令实现分布式锁。
65、缓存雪崩
- 缓存雪崩是指缓存同一时间大面积的失效,导致所有的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉;
解决方案
-
缓存数据过期时间随机,防止同一时间大量数据过期现象发生;
-
热点数据不设置过期时间;
-
检查更新:缓存设置过期时间,当间隔时间小于一个阈值的时主动更新;
-
使用锁:通过互斥锁或者队列,控制读数据库和写缓存的线程数量;
66、缓存穿透
- 缓存击穿是指缓存中没有但数据库中有的数据,这时由于并发用户特别多,读缓存没读到数据,造成数据库短时间内承受大量请求而崩掉。缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是缓存同一时间大面积失效。
解决方案
- 查询返回的数据为空;
67、Redis与Memcached的区别
- 两者都是非关系型内存键值数据库,现在公司一般都是用 Redis 来实现缓存。
68、为什么要用 Redis 而不用 map/guava 做缓存
缓存分为本地缓存和分布式缓存。
- Java 自带的 map 或 guava 是本地缓存,在多实例情况下,每个实例都需要保存一份缓存,缓存不具有一致性;
- Redis 为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性;