7.数据库的存储引擎:
MySQL
中的数据、索引以及其他对象是
如何存储
的,是
一套文件系统的实
现
。 常用的存储引擎:Innodb引擎:支持事务,提供行级锁和外键的约束。常用于电商网站(结账不成功能够回滚)不支持全文索引 MyIASM引擎: 不提供事务的支持,也不支持行级锁和外键(以读写插入为主的应用程序,比如博客系统、新闻门户网站)。
支持全文索引
MEMORY
引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。(断电)
InnoDB
索引是聚簇索引,
MyISAM
索引是非聚簇索引。 (
索引和数据放在同一个文件当中就是聚簇索引,找到了索引也就找到了数据
)
8.
MyISAM
和
InnoDB
存储引擎使用的锁:
MyISAM
采用表级锁
(table-level locking)
InnoDB
支持行级锁
(row-level locking)
和表级锁,默认为行级锁
锁粒度:范围
9.行锁会出现死锁且开销大,但并发能力强,锁冲突概率最低
表锁不会出现死锁,且开销小,但并发能力弱,容易发生锁冲突
10.死锁及其解决:
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。
方法:1、在同一个事务中,尽可能做到
一次锁定所需要的所有资
源,减少死锁产生概率;
2、.
对于非常容易产生死锁的业务部分,可以尝试使用
升级锁定颗粒度
,通过表级锁定来减少死锁产生的
概率;
11.索引覆盖:就是当前查询的Sql语句想要查询的字段已经包含了在当前索引当作了,不用回表,直接将结果返回
12.最左前缀原则:对于联合索引,比如针对a,b,c三个字段建立了一个联合索引,那么在写sql时就一定要提供a字段的条件,因为底层的B+树是按照a,b,c三个字段从左往右去比较大小进行排序的。
13.Innodb是如何实现事务的:
Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例: 1.Innodb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中(内存中) 2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据 3。针对update语句生成—个RedoLog对象,并存入LogBuffer中 4.针对update语句生成
undolog日志,用于
事务回滚 5.如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据页持久化到磁盘中 6.如果事务回滚,则利用undolog日志进行回滚
14.Mysql慢查询该如何优化: 1.检查是否走了索引,如果没有则优化SQL利用索引 2.检查所利用的索引,是否是最优索引 3,检查所查字段是否都是必须的,是否查询了过多字段,查出了多余数据4.检查表中数据是否过多,是否应该进行分库分表了 5.检查数据库实例所在机器的性能配置,是否太低,是否可以适当增加资源
15.Redis有哪些数据结构?分别有哪些典型的应用场景?Redis的数据结构有:
1.字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、Session共享、分布式ID
2.哈希表:可以用来存储一些key-value对,更适合用来
存储对象
3.列表: Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等
消息流数据(双向链表来实现)
4.集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似,
我和某人共同关注的人、朋友圈点赞等功能
5.有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现
排行榜功能。每个元素包含数据本身和一个对应的分数(score),zset的数据本身不允许重复,但是score允许重复
16.分布式锁:
分布式锁是控制分布式系统之间
同步访问
共享资源的一种方式,不同系统或者同一系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,需要通过一定的互斥手段来防止彼此的干扰,以保证一致性。
Redis实现分布式锁(Redis支持基本的事务操作):
SET key value NX EX second
实现分布式锁,当指定键不存在时,向Redis
中添加一个键值对,并设置过期时间,需要释放锁时,使用get key 比较前后value是否一致,如果一致,使用delete删除键即可,否则会进行回滚(其他客户端改变了键值对)(最重要的)
然后还要利用lua脚本来保证多个redis操作的原子性
同时
还要考虑到锁过期
,所以需要额外的一个看门狗(watch dog)定时任务来
监听锁是否需要续约
同时还要考虑到redis节点挂掉后的情况,所以需要采用红锁的方式来同时向N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到
17.Redis的数据结构有:
1.字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,
Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、Session共享、分布式ID
2.哈希表:可以用来存储一些key-value对,更适合用来存储
对象
3.列表:Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等
消息流数据
4.集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似,
我和某人共同关注的人、朋友圈点赞等功能
5.有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现排行榜功能
18. 缓存穿透、缓存击穿、缓存雪崩分别是什么
缓存中存放的大多都是
热点数据,目的就是可以让请求直接从缓存中获取到数据,而不用访问Mysql.
1,缓存雪崩:如果缓存中某一时刻
大批热点数据同时过期,那么就可能导致大量请求直接访问Mysql了,解决办法就是在过期时间上增加一点随机值,另外如果搭建一个高可用的Redis集群也是防止缓存雪崩的有效手段
2.缓存击穿:和缓存雪崩类似,缓存雪崩是大批热点数据失效,而缓存击穿是指
某一个热点key突然失效,也导致了大量请求直接访问Mysql数据库,这就是缓存击穿,解决方案就是考虑
这个热点key不设过期时间
3,缓存穿透:假如某一时刻访问redis的
大量key都在redis中不存在(比如黑客故意伪造一些乱七八糟的key),那么也会给数据造成压力,这就是缓存穿透,解决方案是使用
布隆过滤器,它的作用就是如果它认为一个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加一层布隆过滤器来拦截不存在的key
19.Redis和Mysql如何保证数据一致
延时双删(删了两次redis),步骤是:先删除Redis缓存数据,再更新Mysql,延迟几百毫秒再删除Redis缓存数据,这样就算在更新Mysq时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删除掉,从而保持数据一致.
20. 互斥同步锁(
悲观锁) 非互斥同步锁(
乐观锁):
什么是悲观镇。什么是乐观锁?
悲观锁:修改数据把数据锁住,在更改。别人此时无法访问 synchronized和Lock类
乐观锁:常用就是
CAS(
比较和替换
)算法。
版本号,原子类AtomicInteger
实际场景举例;
乐观锁(
假设不会发生并发冲突):
push代码到仓库 先检查版本号,版本号不一致的话就得先拉取,在合并,然后上传,一致的话就直接上传
悲观锁(
假定必发生并发冲突):数据库中select xxo for update;
乐观锁添加一个字段version =1; 如果某个线程改掉过这行记录,version =2;此时进行update xcxcx where version =1 这个就无效
悲观锁的劣势:1、阻塞、唤醒,性能劣势 阻塞需要排队,唤醒需要时间 乐观锁的效率高于悲观锁; 2、永久阻塞(永远不能释放锁) 3、优先级,阻塞的优先级越高,持有锁的优先级就越低。导致优先级反转的问题 也就是优先级低的线程拿到锁,会阻塞优先高的线程拿到锁
适用场景
乐观锁:并发
写入少,大多数都是读操作。
悲观锁:
并发写入多的情况,临界区有IO操作,临界区代码复杂,临界区竞争激烈
21. for update
select查询语句是不会加锁的,但是select .......for update除了有查询的作用外,还会加锁呢,而且它是悲观锁。那么它加的是行锁还是表锁,这就要看是不是用了索引/主键。没用索引/主键的话就是表锁,否则就是是行锁。 锁住了就会阻塞(执行写操作时)
22.视图:
是一种虚拟表,在物理上是不存在的,其内容与真实的表相似,是从
一个或几个基本表
(或视图)导出的表,基表中的数据发生变化,从视图中查询出的数据也随之改变,视图的建立和删除不影响基本表,
对视图内容的更新(添加,删除和修改)直接影响基本表
。是为了提高复杂SQL语句的复用性和
表操作的安全性。
当视图来自多个基本表时,不允许添加和删除数据。
视图的作用
:保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限
;
23.Sql语句分为几类:
数据定义语言 DDL(Data Definition Language): Create drop alter
数据查询语言 DQL(
Data Query Language
):
Select
数据操纵语言DML
(
Data Manipulation Language
)
Insert
,
Update
,
Delete
数据控制功能
DCL
(
Data Control Language
):
Grant
,
Revoke
,
Commit
,
Rollback
24.非聚簇索引不一定会回表查询,
这取决于查询语句所要求的字段
是否全部命中了索引
,如果全部命中了索引,那么就不必再进行回表查询
假设我们在员工表的年龄上建立了索引,那么当进行select age from employee
where age < 20
的查询时,在索引的叶子节点上,已经包含了
age
信息,不会再次进行回表查询
25. int(20)中的20 指
显示字符的长度
,但仍占
4
字节存储,
存储范围不变
char(10)
表示存储定长的
10
个字符,不足
10个就用空格补齐,空格表示占位不算一个字符
varchar(10)
表示存储
10个变长的字符,,空格也按一个字符存储
26. drop
、
delete
与truncate的区别
delete是逐行删除表中数据,速度慢,
可回滚
truncate是直接删除表中数据 ,
不可回滚
上面两个操作
表结构都还在
,只是表数据没了
而drop是直接
从数据库中删除表
,索引和权限都会被删除,
不可回滚
27. explain语句结果中各字段的含义
type (
非常重要,可以看到
有没有走索引
)
访问类型
key 实际上使用的索引
key_len 实际使用到的索引长度
rows 预估需要读取的记录条数
28.
字段为什么要求定义为
not null
?
null值会占用更多的字节
,且会在程序中造成很多与预期不符的情况。
29. CRUD比较慢,如何优化?分库分表该怎么做:
1. 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单 历史的时候,我们可以控制在一个月的范围内。;
2. 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
3. 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;
4. 通过分库分表的方式进行优化:
①垂直分表(一张表中的列进行拆分):
根据数据库里面
数据表列的相关性进行拆分
。 例如,用户表中既有用户的登录信息又有用户的基本信息,
可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。有点:行数据变少,简化表的结构,易于维护 缺点:主键会出现冗余,让事务变得复杂
②水平分表(一张表中行进行拆分)
30.Mysql
默认隔离级别:
Repeatable Read
31.分布式锁一般有三种实现方式:①。
基于Redis的分布式锁 ②。
基于ZooKeeper的分布式锁(使用
顺序节点和
临时节点的特性,临时节点:客户端与服务器端建立连接时创建,断开连接时删除。 顺序节点:当客户端进行请求时,先创建节点,然后比较节点的序号,当比自己序号小的节点并没有占用资源时,则使用,否则进入循环等待) ③。数据库的乐观锁,实际上就是
创建一张新表,请求占用时就insert(利用主键和唯一索引的特性),删除时则delete。
主流的实现方式就前两种。zookeeper分布式锁的特点是
高一致性,因为zookeeper保证的是
CP,所以由它实现的分布式锁更可靠,不会出现混乱。redis分布式锁的特点是
高可用,因为redis保证的是
AP,所以由它实现的分布式锁可能不可靠,不稳定(一旦redis中的数据出现了不一致),可能会出现多个客户端同时加到锁的情况。
- 一致性(C:Consistency)
- 可用性(A:Available)
- 分区容错性(P:Partition Tolerance)
32.分布式ID的生成方案:
自增的就容易泄密,随机的话索引效率太低
最好的就是雪花算法,在java中雪花算法生成的id(64位)是用Long存储的 ,snowflake可以保证所有生成的id是按时间趋势递增,而且在整个分布式系统内不会产生重复id(因为有时间戳和工作机器id)
33. Redis持久化,Redis是单线程
RDB:快照的形式,比如说每一个小时保存一次当前的快照
AOF:二进制文件,每次写操作的时候才会记录
AOF文件保存的数据集比RDB要完整
34.Redis缓存回收
是因为内存满了,需要释放一些,而Redis删除缓存是因为用不到了,或者过期了
以上这种策略还是得根据具体业务来选定
35.常见的集群分类
①主从复制集群 ②分片集群(分而治之)
36.分布式锁的使用原因:
在单体架构中,多个线程都是属于同一个进程的,所以在线程并发执行时,遇到资源竞争时,可以利用ReentrantLock synchronized等技术来作为锁,来控制共享资源的使用。
而在分布式架构中,多个线程是可能处于不同进程中的,而这些线程并发执行遇到资源竞争时,利用ReentrantLock.synchronized等技术是没办法来控制多个进程中的线程的,所以需要分布式锁,意思就是,需要一个分布式锁生成器,分布式系统中的应用程序都可以来使用这个生成器所提供的锁,从而达到多个进程中的线程使用同一把锁。