数据库
探索数据库基础、数据存储模式,以及常见后端数据库选择之间的权衡。
数据库存在的原因
应用程序需要一种可靠的方式来存储和检索数据,这些数据能够在单次程序执行之外持续存在。
应用
数据库
数据在内存中创建(临时)
- 数据库提供持久化存储,因此数据在重启和故障后仍然存在。
- 它们支持高效查询,能够快速检索特定数据。
- 它们保证一致性,并支持来自多个用户或服务的并发访问。
详情
在真实世界的系统中,应用程序会不断生成并依赖各种数据,例如用户账户、交易、消息和日志。将这些数据直接存储在应用程序内存中是不够的,因为内存是临时的,当程序停止或崩溃时就会消失。
数据库通过提供持久化存储来解决这个问题。数据会以一种能够在重启和系统故障后仍然保留的方式写入磁盘。这正是银行平台、社交网络和电子商务网站等系统能够维护长期状态的原因。
除了存储之外,数据库还提供了结构化的数据访问方式。开发者不必手动扫描文件,而是可以使用查询精确获取所需内容。例如,根据邮箱获取用户,或者检索过去一周的所有订单。
数据库还会强制执行一致性规则,确保即使多个操作同时发生,数据仍然保持有效。如果没有这些机制,系统在并发访问下很容易损坏数据。
从高层来看,数据库充当系统记录的来源。应用程序负责处理请求,而数据库负责存储和管理这些请求所依赖的数据。
SQL 数据库
SQL 数据库将数据组织到具有明确定义的 schema 和关系的结构化表中,从而实现可靠且一致的数据管理。
结构化表将数据组织为行和列
- 数据存储在表中,以行和列的形式组织,形成结构化格式。
- Schema 通过精确定义数据必须如何存储来保证一致性。
- 关系型查询允许跨多个表组合数据。
详情
SQL 数据库遵循关系模型,其中数据被组织成表。每个表表示一个实体(例如用户或订单),每一行表示该实体中的一条记录。
一个关键特性是 schema。在存储数据之前,你需要定义结构,包括列类型和约束。这可以确保所有数据都遵循一致的格式,从而减少错误并保持完整性。
表之间的关系是 SQL 系统的核心。例如,用户表可以通过 user_id 与订单表关联,使系统能够高效地连接相关数据。
SQL 数据库还支持强大的查询能力。借助 joins、filters 和 aggregations,开发者可以在一次查询中从多个表中检索复杂数据集。
这种结构化方法提供了很强的一致性和可靠性,这也是 PostgreSQL 和 MySQL 等 SQL 数据库在正确性和数据完整性至关重要的系统中被广泛使用的原因。
NoSQL 数据库
NoSQL 数据库通过允许不同的数据模型,而不是固定的关系结构,来优先考虑灵活性和可扩展性。
灵活的模式 — 记录不需要完全相同的结构
不同的数据模型 — 不局限于表
直接查找 — 简单的键 → 值访问
水平扩展 — 数据分布在多台机器上
- NoSQL 数据库使用灵活的 schema,允许数据在没有严格结构的情况下演进。
- 它们支持多种数据模型,例如 document、key-value、wide-column 和 graph。
- 它们专为高可扩展性和处理大规模分布式数据集而设计。
详情
与 SQL 数据库不同,NoSQL 系统不需要预定义的 schema。这意味着每条记录都可以有不同的结构,因此当数据是非结构化的或经常变化时,它们非常有用。
不同的 NoSQL 数据库针对不同的使用场景进行了优化。像 MongoDB 这样的 document 数据库存储类似 JSON 的对象,像 Redis 这样的 key-value 存储提供极快的查找,像 Cassandra 这样的 wide-column 数据库处理海量分布式数据集,而 graph 数据库则直接对关系建模。
这种灵活性使 NoSQL 系统更容易在许多服务器之间进行水平扩展,这对于处理高流量的大规模应用至关重要。
代价是,许多 NoSQL 系统会牺牲严格一致性或复杂的关系查询,以换取性能和可扩展性。选择 SQL 还是 NoSQL 取决于数据的结构以及系统的需求。
索引
索引通过让数据库无需扫描整张表就能定位行,从而加快数据检索速度。
- 没有索引时,数据库会扫描每一行(全表扫描)。
- 有索引时,数据库会执行快速查找来找到匹配的数据。
- 索引可以提升读取性能,但会增加写入和存储开销。
详情
当查询在没有索引的情况下运行时,数据库必须逐行检查每一行来找到匹配结果。这称为全表扫描,随着数据集变大,它会变得非常慢。
索引就像一种查找结构(类似书籍的索引)。数据库不需要扫描全部内容,而是可以直接跳到数据所在的位置。这会显著减少查询时间,尤其是在大表上。
例如:
CREATE INDEX idx_users_email ON users(email);
这会在 email 列上创建一个索引,使像“按 email 查找用户”这样的查询执行得更快。
不过,索引并不是免费的。每次插入、更新或删除数据时,索引也必须同步更新。这会让写入稍微变慢,并增加存储使用量。
有效的数据库设计需要选择合适的列来建立索引——通常是那些在搜索条件、过滤或连接中经常使用的列。
事务
事务将多个操作组合成一个单元,这样要么所有更改都成功,要么都不应用。
- 事务确保多个相关操作被视为一个原子单元。
- 如果所有步骤都成功,更改就会提交;如果任何一步失败,所有更改都会回滚。
- 它们可以防止复杂更新过程中出现不一致的数据。
详情
在许多系统中,操作并不是彼此隔离的。例如,在两个账户之间转账需要同时更新两个余额。如果一个更新成功而另一个失败,系统就会变得不一致。
事务通过将操作组合在一起来解决这个问题:
BEGIN UPDATE account A UPDATE account B COMMIT
如果在执行过程中任何一步失败,数据库就会执行回滚,撤销事务中之前的所有更改。
这保证了不会发生部分更新。要么整个操作成功完成,要么系统恢复到之前的状态。
事务在正确性很重要的系统中至关重要,例如金融系统、库存跟踪和预订系统。没有事务,故障或并发问题很容易破坏数据。
ACID 属性
ACID 属性定义了使数据库事务可靠且安全的保证。
- 原子性确保事务中的所有操作要么全部完成,要么全部失败。
- 一致性保证数据库始终保持在有效状态。
- 隔离性和持久性确保事务之间不会相互干扰,且已提交的数据是永久的。
详情
ACID 是关系型数据库为确保事务期间正确性而强制执行的四个属性。
原子性 表示事务是不可分割的。如果任何一步失败,整个事务都会回滚,从而防止部分更新。
一致性 确保事务完成后,数据库遵守所有规则,例如约束、关系和数据有效性。绝不允许无效状态。
隔离性 确保同时运行的多个事务不会相互干扰。即使在并发系统中,每个事务的行为也像是单独运行一样。
持久性 保证一旦事务被提交,数据就会被永久保存,即使系统在提交后立即崩溃也是如此。
这四个属性共同使数据库能够在不破坏数据的情况下处理故障、并发和复杂操作。它们是构建可靠系统的基础,而在这些系统中,正确性至关重要。
查询优化
数据库使用查询优化来确定执行查询的最有效方式。
- 查询规划器会分析查询并选择高效的执行策略。
- 它决定如何访问数据,例如使用索引而不是全表扫描。
- 优化可以降低大型数据集的延迟和资源使用。
详情
当你向数据库发送查询时,它不会机械地逐步执行。相反,数据库会先使用一个称为查询规划器的组件来分析查询。
规划器会评估多种可能的执行方式,并选择最有效的一种。这包括是否使用索引、如何连接表,以及操作顺序等决策。
例如,如果某个查询通过 email 查找用户,并且该列上存在索引,数据库就会使用索引,而不是扫描每一行。在大型数据集上,这可以将执行时间从几秒缩短到几毫秒。
这个过程的结果是一个执行计划,它精确定义了查询在内部将如何运行。
随着数据增长,查询优化变得至关重要。优化不佳的查询会导致响应缓慢、CPU 使用率高以及系统瓶颈;而优化良好的查询则能让系统保持快速并具备可扩展性。
复制
复制通过将数据复制到多个数据库实例来提高可靠性和可扩展性。
- 数据从主数据库复制到一个或多个副本。
- 写入通常发送到主库,而读取可以分布到各个副本上。
- 复制可以提高可用性、容错能力和读取性能。
详情
复制用于在不同的数据库服务器上保留同一份数据的多个副本。最常见的架构是主从复制模型。
在这种模型中,主数据库处理所有写操作。随后,所做的任何更改都会传播到副本数据库。这些副本保存数据副本,并且可以处理读取请求。
这种架构带来几个好处。如果主数据库发生故障,某个副本可以接管,从而提高系统可用性。它还允许系统通过将查询分散到多个副本上来扩展读取流量,而不是让单个数据库过载。
不过,复制也会引入复杂性。数据写入主库与其出现在副本上之间可能会有轻微延迟(replication lag)。这意味着副本不一定总是拥有最新的数据。
尽管存在这种权衡,复制仍然是构建可扩展且具备容错能力的后端系统的核心技术。
分片
分片通过将数据分散到多个服务器上来扩展数据库,而不是依赖单个系统。
- 数据被划分为多个分片,每个分片存储总数据集的一部分。
- 分片通过增加更多数据库服务器来实现水平扩展。
- 它将负载分布到多台机器上,以处理大规模数据集和高流量。
详情
随着数据增长,单个数据库服务器最终会成为瓶颈。分片通过将数据拆分成更小的部分来解决这个问题,每个分片存储在不同的服务器上。
例如:
分片 1 → 用户 1–1M
分片 2 → 用户 1M–2M
分片 3 → 用户 2M–3M
请求会根据正在访问的数据路由到正确的分片。这使系统能够水平扩展并处理更大的工作负载。
代价是复杂性增加,尤其是在查询需要来自多个分片的数据时。
问题部分
1 / 5
此课程属于高级内容
升级到高级版以去除模糊效果并解锁完整内容。