一些Mysql和Redis基础知识
一、MySQL的事务隔离级别有几种?
1. 读未提交(Read Uncommitted)
- 定义:事务可以读取其他未提交事务的修改。可能导致脏读。
- 特点:最低的隔离级别,性能最好,但数据一致性最差。
2. 读已提交(Read Committed)
- 定义:事务只能读取已提交事务的修改。避免了脏读。
- 特点:每次读取数据时,都会看到当前已提交的最新数据,但可能会出现不可重复读。
3. 可重复读(Repeatable Read)
- 定义:在同一事务中,多次读取同一数据项的值都是相同的。避免了脏读和不可重复读。
- 特点:MySQL的默认隔离级别,使用MVCC来实现,能够防止幻读,但在某些情况下可能仍然会出现幻读(如插入新行)。
4. 串行化(Serializable)
- 定义:最高的隔离级别,强制事务串行执行,完全避免了幻读、不可重复读和脏读。
- 特点:性能最低,但数据一致性最好。
二、幻读是什么?会出现在哪种隔离级别下
1. 定义
- 幻读(Phantom Read):幻读是指在同一事务中,多次读取同一查询条件的数据时,发现结果集发生了变化(如新增或删除了行)。
例如,事务A在查询某个范围的数据后,事务B在此期间插入了一条新记录,导致事务A再次查询时结果集发生变化。
2. 出现的隔离级别
可重复读(Repeatable Read)和 读未提交(Read Uncommitted)
三、可重复读会出现幻读吗?
1. 特性
在MySQL中,可重复读(Repeatable Read)隔离级别通过MVCC机制可以防止脏读和不可重复读,但在某些情况下仍然可能发生幻读。这是由于在某些查询中,插入新记录可能导致查询结果集的变化。 例如,假设事务A在执行某个范围查询时,事务B在此期间插入了一条符合查询条件的新记录,事务A再次执行查询时,会发现结果集发生了变化,这就是幻读的表现。
四、MVCC(多版本并发控制)
1. 定义
MVCC(多版本并发控制)是数据库管理系统中一种并发控制机制,它允许多个事务并发执行,并确保数据一致性。MVCC通过记录每个事务对数据的修改,并生成一个版本控制表,来管理并发事务对数据的访问。
2. 工作原理
MVCC的工作原理如下:
- 版本管理:每次对数据的修改都会生成一个新的版本,旧版本仍然保留,允许其他事务读取。
- 时间戳:每个事务在开始时会被分配一个时间戳,读取数据时会根据时间戳确定可见的版本。
- 快照读取:在可重复读隔离级别下,事务读取数据时会看到一个快照,确保读取到的是事务开始时的数据状态。
3. 优点
- 提高并发性:多个事务可以并发读取数据,而不需要等待其他事务释放锁。
- 减少锁竞争:通过避免长时间持有锁,降低了事务间的干扰。
4. 实例
在MySQL中,MVCC通过InnoDB存储引擎实现。当一个事务开始时,它会看到一个一致的快照,所有修改在事务提交之前对其他事务不可见。
五、redo log和undo log的作用
1. redo log(重做日志)
- 作用:用于保证事务的持久性(Durability)。在事务提交后,redo log记录了所有修改操作的日志,以便在系统崩溃后能够恢复未持久化的数据。
- 实现机制:当事务提交时,先将修改记录写入redo log,再将数据写入数据文件。即使系统崩溃,重启后可以通过redo log重做未持久化的操作,确保数据不丢失。
2. undo log(撤销日志)
- 作用:用于支持事务的原子性(Atomicity)和一致性(Consistency)。当事务需要回滚时,undo log记录了所有操作的反向操作,以便能够撤销已执行的操作。
- 实现机制:每当进行数据修改时,undo log会记录该操作的反向操作。如果事务回滚,系统会根据undo log将数据恢复到修改前的状态。
六、从ACID层面探讨,redo log和undo log是否能保证?
1. 原子性(Atomicity)
保证方式:通过undo log实现。如果事务未能成功完成,可以使用undo log撤销所有已执行的操作,确保事务的原子性。
2. 一致性(Consistency)
保证方式:在事务开始和结束时,系统状态保持一致。通过使用undo log和redo log,确保在事务回滚或崩溃恢复时,数据保持一致。
3. 隔离性(Isolation)
保证方式:虽然redo log和undo log主要用于持久性和原子性,但它们结合MVCC等机制也有助于实现事务之间的隔离性。
4. 持久性(Durability)
保证方式:通过redo log实现。事务提交后,所有修改会被记录到redo log中,即使系统崩溃,也能通过redo log恢复数据。
七、额外保证ACID
- 锁机制:用于实现事务之间的隔离性,防止并发事务对同一数据的冲突。
- 时间戳机制:用于确保事务的顺序性和一致性,特别是在高并发环境下。
- 一致性检查:在事务开始和结束时检查数据的一致性,确保不违反业务规则。
- 故障恢复机制:在系统崩溃时,能够通过日志和快照恢复数据状态。
八、MySQL的索引是如何做的?为什么能做到这么快的查找?有什么优缺点?
1. 索引的实现
- 数据结构:MySQL主要使用B+树和哈希表作为索引的底层数据结构。
- B+树索引:在B+树中,所有值都存储在叶子节点,非叶子节点只存储键值,树的高度较低,查找效率高。
- 哈希Hash索引:适用于等值查询,通过哈希函数将键映射到存储位置。
2. 快速查找的原因
- 减少I/O操作:索引可以显著减少需要扫描的数据量,从而减少磁盘I/O操作,提高查找速度。
- 树结构:B+树的层高通常较低,查找路径短,能够快速定位到目标数据。(B+树的层高一般为O(log n),其中n为树中的元素总数,因此查找效率较高。)
3. 节点与节点之间的联通
- 叶子节点:B+树的所有叶子节点通过指针相连,形成一个链表结构。这使得范围查询和遍历操作变得高效。
- 非叶子节点:非叶子节点通过指向子节点的指针进行连接,形成树形结构。
4. 优缺点
- 优点: 提高查询效率。 加速排序和聚合操作。
- 缺点: 增加存储空间开销。 在数据插入、更新和删除时需要维护索引,可能导致性能下降。
九、最左匹配原则
1. 定义
最左匹配原则是指在使用复合索引时,查询条件中必须从左到右依次匹配索引的列,才能有效利用索引。
2. 例子
假设有一个复合索引 (A, B, C),以下查询能有效使用索引:
- WHERE A = 1 AND B = 2(符合最左匹配原则)
- WHERE A = 1(符合最左匹配原则)
以下查询不能有效使用索引:
- WHERE B = 2(不符合最左匹配原则)
- WHERE C = 3(不符合最左匹配原则)
3. 影响
遵循最左匹配原则可以提高查询效率,确保索引的有效利用,从而加快数据检索速度。
十、聚簇索引和非聚簇索引的区别
1. 聚簇索引(Clustered Index)
1.1 定义
聚簇索引是将数据存储在索引中的一种方式,数据行的物理顺序与索引的顺序相同。每个表只能有一个聚簇索引。
1.2 特性
- 数据和索引存储在同一结构中,查找时直接定位到数据行。
- 适合范围查询,性能较高。
- 更新时可能导致数据行的移动,从而影响性能。
2. 非聚簇索引(Non-Clustered Index)
2.1 定义
非聚簇索引是指索引与数据存储分开,索引中存储的是数据行的指针(或行号),每个表可以有多个非聚簇索引。
2.2 特性
- 数据和索引分开存储,查找时需要先通过索引找到指针,再定位到数据行。
- 适合单值查询,索引结构较小,更新时对数据行的影响较小。
- 性能相对聚簇索引略低,但灵活性更高。
十一、索引下推
1. 定义
索引下推是一种优化技术,允许数据库在使用索引时,将某些查询条件下推到索引扫描阶段,而不是在获取完整数据后再进行过滤。
2. 优势
- 提高性能:通过在索引层面过滤不必要的数据,减少了需要读取的数据量,从而提高查询效率。
- 减少I/O操作:降低了对数据页的访问频率,减少了磁盘I/O。
3. 适用场景
当查询条件中有多个列,并且这些列被包含在索引中时,索引下推能够显著提高查询性能。
十二、慢查询的定位与优化
1. 定位慢查询
- 开启慢查询日志:在MySQL配置文件中设置slow_query_log为ON,并设置long_query_time以记录超过指定时间的查询。
- 使用EXPLAIN命令:对慢查询使用EXPLAIN语句,分析查询的执行计划,查看索引是否被使用。
- 性能分析工具:使用工具如pt-query-digest分析慢查询日志,找出瓶颈。
2. 优化方法
- 优化索引:根据查询条件添加合适的索引,避免全表扫描。
- 调整查询语句:重写查询语句,避免复杂的联接和子查询。
- 分表分库:对大表进行分表分库,减少单表数据量。
- 增加缓存:使用缓存机制(如Redis)缓存频繁查询的数据,减少数据库压力。
十三、分库分表的注意事项及策略
1. 分库分表策略
- 按业务功能分库:将不同业务模块的数据放入不同的数据库中。
- 按用户ID或地理位置分表:根据用户ID的哈希值或地理位置将数据分散到不同的表中。
- 水平分表:将大表按行数分割,形成多个小表。
- 垂直分表:将表按列分割,将不同的字段放入不同的表中。
2. 注意事项
- 数据一致性:确保在分库分表后,数据的一致性和完整性得到保证。
- 查询性能:考虑跨库查询的性能,尽量减少跨库操作。
- 事务管理:分库分表后,事务的管理和回滚变得复杂,需要使用分布式事务管理。
- 扩展性:设计时要考虑未来的扩展性和易维护性。
- 负载均衡:合理分配负载,避免某个库或表的性能瓶颈。
十四、分区和分表的区别
1. 分区(Partitioning)
1.1 定义
将一个表的数据分散存储在不同的物理位置,但从逻辑上仍然是一个表。
1.2 特性
- 数据在同一表中,使用分区键进行划分。
- 支持范围分区、列表分区、哈希分区等。
- 适合大表的管理,提高查询性能,简化管理。
2. 分表(Sharding)
2.1 定义
将数据拆分到多个物理表中,通常是根据某种规则(如用户ID)将数据分散到不同的表。
2.2 特性
- 每个表是独立的,通常在不同的数据库实例中。
- 可以根据业务需求灵活扩展。
- 适合高并发和大量数据场景。
十五、Redis的数据类型(详情看小林coding)
1. 字符串(String):
最基本的数据类型,可以存储任何形式的数据,包括文本、数字等。
2. 哈希(Hash):
用于存储键值对的集合,适用于表示对象。
3. 列表(List):
有序的字符串集合,可以在两端进行插入和删除操作,适合实现队列和栈。
4. 集合(Set):
无序的字符串集合,支持集合运算(如交集、并集、差集)。
5. 有序集合(ZSet):
类似于集合,但每个元素都有一个分数,按分数排序,支持范围查询。
6. 位图(Bitmap):
对字符串的位操作,常用于统计和计数。
7. 超日志(HyperLogLog):
用于基数统计,能够高效地估算唯一元素的数量。
8. 地理空间(Geospatial):
用于存储和查询地理位置数据。
十六、ZSet的底层实现
1. 定义
ZSet(有序集合)是Redis中的一种数据类型,每个元素都有一个分数,元素按分数排序。
2. 底层实现
- 跳表(Skip List):
-
- Redis使用跳表作为ZSet的主要数据结构。跳表是一种随机化的数据结构,允许快速的插入、删除和查找操作,时间复杂度为O(log n)。
-
- 跳表由多个层级组成,每个层级都是一个有序链表,底层包含所有元素,越往上层包含的元素越少。
- 哈希表: Redis还使用哈希表来存储ZSet中的元素及其分数,以便在需要时快速查找和更新。
3. 优势
- 高效性:跳表支持快速的范围查询和排名操作,适合实时数据处理。
- 灵活性:可以存储重复元素和分数相同的元素,便于复杂应用场景。
十七、压缩列表的结构
1. 定义
压缩列表(Ziplist)是Redis中用于存储小数量元素的高效数据结构,主要用于节省内存。
2. 结构特点
- 扁平结构:压缩列表是一个连续的内存块,其中包含多个元素,元素之间没有指针,节省了指针的内存开销。
- 元素存储:每个元素包含长度信息和实际数据,支持字符串和整数类型。
- 动态调整:当元素数量超过一定阈值时,压缩列表会被转换为其他数据结构(如链表或哈希表)。
3. 优势
- 节省内存:由于没有额外的指针开销,适合存储小型数据。
- 快速访问:对于小数据量的操作,压缩列表提供了快速的访问性能。
4. 缺点
- 性能限制:当元素数量较多时,压缩列表的性能会下降,因此适用于小数量元素的场景。