MySQL
1、MySQL 中的 varchar 和 char 有什么区别?
- char 是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容,该字段都占用 10 个字符;而 varchar 是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1。
- 在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用 char,否则应该尽量使用 varchar。
2、MySQL 执行查询的过程
- 连接:客户端通过 TCP 连接发送连接请求到 MySQL 连接器,连接器会对该请求进行权限验证及连接资源分配
- 查缓存:当判断缓存是否命中时,MySQL 不会进行解析查询语句,而是直接使用 SQL语句和客户端发送过来的其他原始信息。所以,任何字符上的不同,例如空格、注解等都会导致缓存的不命中。
- 语法分析:分析SQL 语法是否写错了,以及如何把语句给到预处理器,检查数据表和数据列是否存在,解析别名看是否存在歧义。
- 优化:是否使用索引,生成执行计划。
- 交给执行器:将数据保存到结果集中,同时会逐步将数据缓存到查询缓存中,最终将结果集返回给客户端。
3、脏读、幻读和不可重复读
- 脏读(提没提交):一个事务读到另一个事务中还未提交的数据,即另一个事务可能回滚。
- 幻读(存不存在):侧重于当前事务获取的数据集或影响的范围无法支撑后续的业务操作;例如查询某数据时发现没有,但插入数据时却又发现当前数据已存在,无法插入。这种像幻觉一样的现象称之为幻读。
- 不可重复读(变没变化):同一个事务中,两次读取的结果不一致。
- 幻读侧重于新增或删除(多了或少量行),而不可重复读侧重于修改
4、MySQL 的四种隔离级别
- Serializable (串行化):通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。(最高隔离级别)
- Repeatable read(可重复读):MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,解决了不可重复读的问题。
- Read committed (读已提交):一个事务只能看见已经提交事务所做的改变。可避免脏读的发生。
- Read uncommitted (读未提交):所有事务都可以看到其他未提交事务的执行结果。
5、索引的数据结构
- 索引的数据结构主要有B+树和哈希表,InnoDB引擎默认的索引类型为B+树索引
- 更新十分频繁的字段不建议使用索引,因为更新操作会变更B+树,重建索引,十分消耗数据库性能
- B树和B+树的区别
- B树中的内部节点和叶子节点均存放键和值,而B+树的内部节点只有键,没有值,叶子节点存放所有的键和值
- B+树的叶子节点是相连在一起的,方便顺序检索,而B树不是
6、数据库优化
- 索引优化:通过一些规则尽量使查询命中索引
- SQL语句优化:例如,避免使用Select *,指定列名;使用limit限制查询范围;避免使用or,可能会导致数据库放弃使用索引
- 建立中间表:对于经常需要联合查询的表,建立中间表以提高查询效率
- 建立冗余字段:增加一些经常查询要用到,但又不会经常需要修改的字段,可以有效提高查询效率
- 使用缓存技术:使用mysql缓存(不常用)
- 垂直或水平分表:把多个字段分配到不同的表中存储;把一个表的数据按照一定规则分到多个表中
- 读写分离:主服务器写,从服务器读
Redis
1、Redis的高性能和高并发
- 高性能:操作缓存就是直接操作内存,速度很快
- 高并发:直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的
2、Redis的两种持久化方式
- RDB(Redis DataBase):快照,RDB在指定的时间间隔内对数据进行快照存储。(默认方式)
- AOF(Append Of Flie):只追加文件,AOF记录对服务器的每次写操作,在Redis重启时会重放这些命令来恢复原数据
3、Redis的集群模式及工作原理
- 主从模式:所有的写请求都被发送到主数据库上,再由主数据库将数据同步到从数据库上。主数据库主要用于执行写操作和数据同步,从数据库主要用于执行读操作缓解系统的读压力
- 哨兵模式:在主从模式上添加了一个哨兵的角色来监控集群的运行状态。哨兵通过发送命令让Redis服务器返回其运行状态。哨兵是一个独立运行的进程,在监测到Master宕机时会自动将Slave切换成Master,然后通过发布与订阅模式通知其他从服务器修改配置文件,完成主备热切
- 集群模式:Redis集群实现了在多个Redis节点之间进行数据分片和数据复制。基于Redis集群的数据自动分片能力,我们能够方便地对Redis集群进行横向扩展,以提高Redis集群的吞吐量。基于Redis集群的数据复制能力,在集群中的一部分节点失效或者无法进行通信时,Redis仍然可以基于副本数据对外提供服务,这提高了集群的可用性
4、Redis内存管理
- 给缓存数据设置过期时间,Redis采用定期过期和惰性过期两种过期策略,每隔一段时间就删除一部分数据,同时在获取数据的时候会检查数据是否过期,过期就删除
- 内存淘汰策略:保证Redis中的数据都是热点数据,最常用的是allkeys-lru,当内存不足以容纳新写入数据时,在键空间中移除最近最少使用的key
5、Redis生产问题
1、缓存穿透:缓存穿透说简单点就是大量请求的 key 是非法的,根本不存在于缓存中,也不存在于数据库中 。这就导致这些请求直接到了数据库上,根本没有经过缓存这一层,对数据库造成了巨大的压力。解决办法如下:
- 清理无效key和布隆过滤器
2、缓存击穿:缓存击穿中,请求的 key 对应的是热点数据 ,该数据存在于数据库中,但不存在于缓存中(通常是因为缓存中的那份数据已经过期) 。这就可能会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力。解决办法如下:
- 设置热点数据永不过期或者过期时间比较长;
- 针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期;
- 请求数据库写数据到缓存之前,先获取互斥锁,保证只有一个请求会落到数据库上,减少数据库的压力
3、缓存雪崩:缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力。 这就好比雪崩一样,摧枯拉朽之势。解决办法如下:
- 采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
- 限流,避免同时处理大量的请求
- 设置不同的失效时间比如随机设置缓存的失效时间
- 设置二级缓存
6、Redis有哪些数据结构
常用的
- 字符串(String): 最基本的类型,可以包含任何数据,比如文本、数字或二进制数据。字符串类型是二进制安全的,可以包含最多 512MB 的内容。
- 列表(List): 简单的字符串列表,按照插入顺序排序。可以在列表的头部或尾部添加元素,也可以读取列表的一个范围内的所有元素。
- 集合(Set): 字符串集合,不允许重复的成员。集合内的元素是无序的,可以执行添加、删除和检测元素是否存在等操作。
- 有序集合(Sorted Set): 不允许重复的成员,每个元素都会关联一个 double 类型的分数。有序集合中的元素可以按照分数进行范围查询和排序。
- 哈希表(Hash): 键值对的集合,适合存储对象。哈希表中的每个键值对的键是字符串,值也是字符串。
不常用的
- 位图(Bitmap) 和 超日志(HyperLogLog):这两种数据结构不是直接作为 Redis 的内置类型存在,而是通过其他类型的组合来实现的。位图通常使用字符串类型来表示,用于进行大规模的位操作;超日志是一种概率数据结构,用于高效地估算集合中唯一元素的数量(基数)。
- 流(Stream): 在 Redis 5.0 版本中引入的新数据结构,用于构建消息队列和实现流式数据处理。流数据结构可以存储消息和消息的元数据,并支持消费者组等功能。
- 空间索引(Geo):用于存储地理位置信息,并对这些信息进行查询。可以执行附近位置的查询,查找给定范围内的地理位置信息。
- 时间序列(Time Series):虽然 Redis 本身没有直接提供时间序列数据结构,但是可以通过有序集合(Sorted Set)和哈希表(Hash)的组合来实现时间序列的功能。
MongDB
1、MongDB简介
- MongoDB是一个基于分布式文件存储的开源数据库系统,属于NoSQL数据库,使用文档(BSON格式)来存储数据,支持动态查询、高可扩展性和高可用性。
- BSON(Binary JSON)是一种类似JSON的二进制表示形式,用于存储MongoDB中的文档数据。
2、MongDB的CRUD操作
- C(Create):创建文档,使用db.collection.insertOne()或db.collection.save()。
- R(Read):读取文档,使用db.collection.find()。
- U(Update):更新文档,使用db.collection.updateOne()或db.collection.replaceOne()。
- D(Delete):删除文档,使用db.collection.deleteOne()或db.collection.deleteMany()。
3、MongDB指定查询条件
- $ eq用于等于
- $ ne用于不等于
- $ gt用于大于
- $ lt用于小于等。
查询集合中所有年龄为30的文档:
db.collection.find({ age: 30 })
查询年龄大于25且小于35的文档:
db.collection.find({ age: { $gt: 25, $lt: 35 } })