系统架构设计师 数据库篇

数据库 📚

🌐 一个系统化的数据集合,它允许用户存储、检索和管理数据。数据库通常由表格组成,这些表格中存储了结构化的数据。每个表格由行(记录)和列(字段)组成,它们分别对应数据项和数据特征。

数据库的主要特点包括:

  • 组织化 📈:数据以表格的形式组织,使得数据之间的关系清晰,便于管理。
  • 可访问性 🔍:用户可以通过查询语言(如SQL)来访问和操作数据。
  • 一致性 🔄:数据库管理系统(DBMS)确保数据的准确性和一致性。
  • 安全性 🔐:数据库提供了用户认证、权限控制等安全机制,以保护数据不被未授权访问。
  • 冗余减少 🗂️:通过数据规范化,数据库减少了数据冗余,提高了数据的一致性。
  • 灵活性 🛠️:数据库保证了数据的持久存储,即使在系统故障的情况下也能恢复数据。
  • 持久性 💾:数据结构可以根据需要进行调整,以适应不断变化的需求。

数据库类型:

关系型数据库 📊

  • 如MySQL、PostgreSQL、Oracle和SQL Server,它们使用表格、行和列来组织数据,并使用SQL作为查询语言。

非关系型数据库(NoSQL)🌐

  • 如MongoDB、Cassandra和Redis,它们不依赖于表格模型,而是使用其他存储数据的方式,如键值对、文档或图形数据库。

数据库并发

在多用户共享系统中,许多事务可能同时对同一数据进行操作。

DBMS控制子系统负责协调并发事务的执行,保证数据库的完整性。

事务的基本概念

事务:用户定义的数据库操作序列,要么全做,要么全不做,是一个不可分割的工作单位。

事务的ACID特性

  • 🔴 原子性(Atomicity):要么全做,要么全不做,不能部分完成。
  • 🔁 一致性(Consistency):事务必须保证数据库从一个一致性状态转移到另一个一致性状态。
  • 🏠 隔离性(Isolation):并发执行的事务之间不会互相影响。
  • 💾 持久性(Durability):一旦事务提交,所做的修改会永久保存在数据库中。

数据不一致问题

  • 📝 丢失修改:两个事务修改同一数据,后提交的事务覆盖前一个事务的结果,导致修改丢失。
  • 🚫 脏数据:事务读取到未提交的修改数据,若修改事务回滚,将导致读取脏数据。
  • 🔄 不可重复读:同一事务两次读取数据,另一个事务在两次读取间修改数据,导致数据不一致。

事务隔离级别

SQL Server 中的事务隔离级别

  • 👀 READ UNCOMMITTED(读取未提交)
    • 允许读取未提交的数据,可能导致脏读。
    • 无法保证数据一致性,但可以提高性能。
    • 适用于对性能要求较高、对一致性要求较低的场景。
  • 🔒 READ COMMITTED(读取已提交)
    • 只能读取已提交的更改,避免脏读。
    • 默认隔离级别,适当平衡一致性和性能。
    • 可能发生不可重复读和幻读。
  • 🔄 REPEATABLE READ(可重复读)
    • 事务在读取数据后,锁定读到的数据行,防止其他事务修改。
    • 防止脏读和不可重复读,但可能发生幻读。
    • 适用于需要多次读取相同数据,并且该数据不能被其他事务修改的场景。
  • 🔓 SNAPSHOT(快照)
    • 提供事务开始时数据的一致性视图,防止脏读、不可重复读和幻读。
    • 使用版本控制技术,可以在不加锁的情况下提供一致性读。
    • 提高并发性能,适用于只读操作较多的场景。
  • 🚧 SERIALIZABLE(可串行化)
    • 最高的隔离级别,完全锁定读到的数据,防止脏读、不可重复读和幻读。
    • 所有事务按顺序执行,确保一致性。
    • 对性能影响较大,适用于对数据一致性要求极高的场景。

Oracle 中的事务隔离级别

  • 🔒 READ COMMITTED(读取已提交)
    • 默认的隔离级别。
    • 只能读取已提交的更改,防止脏读。
    • 使用锁机制防止不可重复读和幻读。
  • 🔄 SERIALIZABLE(可串行化)
    • 与 SQL Server 的 SERIALIZABLE 类似。
    • 提供最高的隔离级别,确保事务按顺序执行。
    • 防止脏读、不可重复读和幻读,但可能导致性能降低。

PostgreSQL 中的事务隔离级别

  • 👀 READ UNCOMMITTED(读取未提交)
    • 实际上在 PostgreSQL 中等同于 READ COMMITTED。
    • 不允许脏读。
  • 🔒 READ COMMITTED(读取已提交)
    • 默认隔离级别。
    • 只能读取已提交的更改,防止脏读。
    • 在同一事务中多次读取数据时,可能会看到其他事务提交的修改。
  • 🔄 REPEATABLE READ(可重复读)
    • 提供一致性的视图,防止脏读和不可重复读。
    • 事务在读取数据后,保证后续读取的相同数据保持一致。
    • 使用多版本控制,可能会出现幻读。
  • 🔓 SERIALIZABLE(可串行化)
    • 提供最高的隔离级别,确保事务按顺序执行。
    • 使用乐观并发控制,检测并防止冲突。
    • 防止脏读、不可重复读和幻读,但可能导致事务被回滚。

MySQL 中的事务隔离级别

  • 👀 READ-UNCOMMITTED(读取未提交)
    • 允许读取尚未提交的数据,可能会导致脏读。
  • 🔒 READ-COMMITTED(读取已提交)
    • 只能读取已提交的数据,防止脏读,但可能发生不可重复读或幻读。
  • 🔄 REPEATABLE-READ(可重复读)
    • 多次读取同一数据结果一致,可防止脏读和不可重复读,但可能发生幻读。
  • 🔓 SERIALIZABLE(可串行化)
    • 最高隔离级别,完全服从ACID,防止脏读、不可重复读和幻读。

封锁协议

处理并发控制的主要方法是采用封锁技术,主要有X封锁和S封锁:

  • 🚫 排他型封锁(X 封锁)
    • 事务对数据对象实现X封锁,只有该事务可以读取和修改数据。
  • 🔄 共享型封锁(S封锁)
    • 事务对数据对象实现S封锁,只允许读取数据,不允许修改。

并发控制技术

Oracle

  • 多种封锁技术,包括数据锁(DML锁)和字典锁。
  • 通过回滚段保证不读"脏"数据和可重复读。
  • 提供有效的死锁检测机制。
伪代码示例 (Oracle)
javascript 复制代码
-- 显式锁定表
LOCK TABLE employees IN EXCLUSIVE MODE;

-- 事务中使用FOR UPDATE来隐式锁定选定的行
BEGIN
  -- 开启事务
  SELECT * FROM employees WHERE employee_id = 123 FOR UPDATE;

  -- 执行更新操作
  UPDATE employees SET salary = salary + 1000 WHERE employee_id = 123;

  -- 提交事务
  COMMIT;
END;

SQL Server

  • 使用行级锁、页级锁、表级锁以及意向锁(Intent Locks)。
  • 支持多种事务隔离级别。
  • 自动检测死锁并终止其中一个事务。
伪代码示例 (SQL Server)
javascript 复制代码
-- 使用SELECT WITH (UPDLOCK)来锁定行
BEGIN TRAN
  SELECT * FROM Employees WITH (UPDLOCK)
  WHERE EmployeeID = 1;

  -- 执行更新操作
  UPDATE Employees
  SET Salary = Salary + 1000
  WHERE EmployeeID = 1;

  -- 提交事务
  COMMIT TRAN

PostgreSQL

  • 使用多版本并发控制(MVCC)处理并发,提高性能。
  • 支持多种事务隔离级别,包括共享锁(S锁)和排他锁(X锁)。
伪代码示例 (PostgreSQL)
javascript 复制代码
-- PostgreSQL中使用SELECT FOR UPDATE来锁定行
BEGIN;
  SELECT * FROM employees WHERE employee_id = 123 FOR UPDATE;

  -- 执行更新操作
  UPDATE employees SET salary = salary + 1000 WHERE employee_id = 123;

  -- 提交事务
  COMMIT;

MySQL

  • InnoDB支持MVCC,允许读不受写操作影响。
  • 使用间隙锁和多版本数据避免幻读。
  • 实现行级锁和表级锁,保证事务串行化调度。
伪代码示例 (MySQL)
javascript 复制代码
-- 使用SELECT FOR UPDATE来锁定行
START TRANSACTION;
  SELECT * FROM employees WHERE employee_id = 123 FOR UPDATE;

  -- 执行更新操作
  UPDATE employees SET salary = salary + 1000 WHERE employee_id = 123;

  -- 提交事务
COMMIT;

索引优化策略

  • 📈 选择性索引:为经常作为查询条件且不常更新的属性创建索引。
  • 🚫 限制索引数量:索引过多会影响UPDATE、INSERT和DELETE的性能。
  • 🕒 分析查询频度:分析每个重要查询的使用频度,建立必要索引。
  • 📉 小数据量无需索引:对于数据量小的关系,不必建立索引。
  • 📈 选择性索引:避免在重复值多的列上建立索引。
  • 🔗 复合索引:常涉及多个列的查询,考虑创建复合索引。
  • 🛠️ 索引维护:定期使用REINDEX命令重建索引,减少碎片。
  • 🕵️ 监控索引性能:通过系统表监控索引使用情况,移除低使用率索引。

避免索引失效的操作

  • 🚫 避免使用函数:WHERE子句中使用函数可能使索引失效。
  • 🚫 避免使用不等式:如!=或<>可能导致全表扫描。
  • 📝 使用参数化查询:避免在WHERE子句中直接使用变量。

查询优化

  • 🏗️ 物化视图:建立物化视图或减少多表查询。
  • 🔄 替换子查询:用不相干子查询替代相干子查询。
  • 📑 仅检索必要属性:只检索需要的属性。
  • 🔐 优化条件子句:用IN子句替换OR子句。
  • 🔄 及时提交:经常提交以尽早释放锁。

数据库的优化策略

SQL Server 优化策略

  • 🔍 使用执行计划分析工具
  • 🛠️ 索引优化
  • 📈 调整表结构和数据类型
  • 🕒 减少锁定
  • ⚙️ 缓存和内存管理

Oracle 优化策略

  • 🔍 使用执行计划分析
  • 🛠️ 索引优化
  • 📊 统计信息和优化器
  • 🕒 减少锁定和提高并发
  • 💽 内存和 I/O 优化

PostgreSQL 优化策略

  • 🔍 使用 EXPLAIN 分析查询计划
  • 🛠️ 索引优化
  • 📊 内存和配置优化
  • 🕒 VACUUM 和 ANALYZE
  • 🧩 表分区和数据归档

MySQL 优化策略

  • 🔍 使用 EXPLAIN 分析查询计划
  • 🛠️ 索引优化
  • 📊 使用慢查询日志
  • 📈 调整缓存和内存设置
  • 🕒 分区表和优化表结构
  • ⚙️ 减少锁定和提高并发

备份与恢复技术

备份方式

  • 💾 物理备份
  • 📜 逻辑备份

物理备份类型

  • 🧊 冷备份
  • 🔥 热备份

按数据量

  • 🔒 完全备份
  • 📈 增量备份
  • 🔄 差异备份

日志文件

事务日志:记录数据库的所有操作,将结果保存在独立文件中,称为日志文件。

  • 🔙 undo log(回滚日志):用于事务回滚和MVCC。
  • 🔄 redo log(重做日志):用于故障恢复,确保事务持久性。
  • 🌐 binlog(归档日志):用于数据备份和主从复制。

总结 🧐

在数据库系统中,为了保持数据的一致性和完整性,必须对并发事务进行有效的控制。ACID特性是确保事务可靠性的关键,而隔离级别则在并发控制中起到了平衡性能与一致性的作用。正确的索引设计和查询优化可以显著提升数据库的性能,同时,合理的备份与恢复策略是数据安全的重要保障。

记忆口诀 🎓

  • 原子性:所有操作,要么全做,要么不做。
  • 一致性:数据状态,始终如一。
  • 隔离性:事务之间,互不干扰。
  • 持久性:一旦提交,永不丢失。

趣味记忆互联网案例故事 🌐

想象一下,你在一家全球连锁的咖啡馆,点了一杯咖啡,这就像是开始一个事务。原子性就像是你要么拿到整杯咖啡,要么就不拿;一致性就像是无论你在哪家分店,咖啡的味道和品质都是一致的;隔离性就像是每个顾客都有自己的独立空间,不受其他顾客影响;持久性则像是你已经付款的咖啡,即使出了店门,你依然拥有这杯咖啡。而并发控制就像是咖啡馆的服务员,确保每个顾客的订单都能正确无误地完成,即使在高峰时段,也能保持秩序和质量。

参与点评
读者朋友们,如果您在阅读过程中,对文章的质量、易理解性有任何建议,欢迎在评论区指出,我会认真改进。

相关推荐
是程序喵呀23 分钟前
MySQL备份
android·mysql·adb
指尖上跳动的旋律30 分钟前
shell脚本定义特殊字符导致执行mysql文件错误的问题
数据库·mysql
一勺菠萝丶41 分钟前
MongoDB 常用操作指南(Docker 环境下)
数据库·mongodb·docker
m0_748244831 小时前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝2 小时前
Redis 介绍和安装
数据库·redis·缓存
wmd131643067122 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!2 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱2 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence2 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
m0_748236582 小时前
《Web 应用项目开发:从构思到上线的全过程》
服务器·前端·数据库