垂直分库和水平分库优缺点

文章探讨了数据库拆分中的水平分库和垂直拆分两种策略。水平分库通过数据行拆分减轻单表查询压力,优点在于表关联简单,但切分规则复杂。垂直拆分则依据列进行,简化表结构,利于数据维护,但可能增加程序中表关联的复杂性。两种方法各有优劣,需根据具体场景选择。
  •  水平分库

以数据库表中的每一行数据进行拆分,分解为多行数据,减轻数据库的单表查询存储压力。

  • 水平分库拆分的优点:

表关联基本能够在数据库端全部完成;
不会存在某些超大型数据量和高负载的表遇到瓶颈的问题;
应用程序端整体架构改动相对较少;
事物处理相对简单,只要切分规则能定义好,基本上较难遇到扩展性限制;

  • 水平切分的缺点:

切分规则相对更为复杂,很难抽象出一个能满足整个数据库的切分规则;
后期数据的维护难度有所增加,人为手工定位数据更为困难;
应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。

  • 垂直拆分

垂直拆分是指表数据列的拆分,关键列之间直接联系,不常用列之间直接联系,把一张列比较多的表拆分成多张表。表的记录并不多,但是字段却很长,表占用空间很大,检索表的时候需要执行大量的IO,严重降低了性能。这时候需要把大的字段拆分到另外一个表,并且该表与原表是一对一的关系。

  • 垂直切分的优点

数据库的拆分简单明了,拆分规则明确
应用程序模块清晰明确,整合容易
数据维护方便易行,容易定位

  • 垂直切分的缺点

部分表关联无法再数据库级别完成,需要在程序中完成
对于访问极其频繁且数据量超大的表仍然存在性能瓶颈,不一定满足需求;
事务处理相对更为复杂;
切分达到一定程度后。扩展性会遇到限制
过度切分可能会带来系统过度复杂而难以维护;

数据库设计与优化中,**垂直分表、水平分表、垂直分库水平分库**是常见的数据拆分策略,用于解决单表/单库数据量过大、性能瓶颈、I/O压力等问题。下面我将详细解释这四种方式,并提供示例代码说明(以MySQL为例),最后提出相关问题。 --- ### 一、垂直分表(Vertical Partitioning) #### ✅ 定义: 将一个宽表按照“列”进行拆分,把不常用的或大字段(如 `text`、`blob`)分离到另一张表中,主表保留高频访问的字段。 #### ✅ 目的: - 减少 I/O 开销 - 提高查询效率(尤其是只查核心字段时) - 分离冷热数据 #### ✅ 示例: 原始表 `user`: ```sql CREATE TABLE user ( id INT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100), phone VARCHAR(20), profile TEXT, -- 大文本字段 avatar BLOB, -- 图片二进制 created_at DATETIME ); ``` 拆分为两个表: ```sql -- 核心信息表(高频访问) CREATE TABLE user_core ( id INT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100), phone VARCHAR(20), created_at DATETIME ); -- 扩展信息表(低频访问) CREATE TABLE user_ext ( user_id INT PRIMARY KEY, profile TEXT, avatar BLOB, FOREIGN KEY (user_id) REFERENCES user_core(id) ); ``` #### ✅ 查询示例: ```sql -- 只查基本信息(快) SELECT name, email FROM user_core WHERE id = 1; -- 查完整信息(需 JOIN) SELECT uc.name, uc.email, ue.profile FROM user_core uc LEFT JOIN user_ext ue ON uc.id = ue.user_id WHERE uc.id = 1; ``` > ⚠️ 缺点:需要 `JOIN`,复杂度增加。 --- ### 二、水平分表(Horizontal Partitioning / Sharding by Row) #### ✅ 定义: 按“行”拆分,将数据根据某种规则(如 ID 取模、时间范围等)分散到多个结构相同的表中。 #### ✅ 目的: - 解决单表数据量过大导致的性能下降 - 改善查询写入速度 #### ✅ 示例: 原始表: ```sql CREATE TABLE order_0 ( id BIGINT PRIMARY KEY, user_id INT, amount DECIMAL(10,2), create_time DATETIME ); ``` 拆分为多张表(按 user_id 取模): ```sql CREATE TABLE order_0 (like order_template); CREATE TABLE order_1 (like order_template); CREATE TABLE order_2 (like order_template); -- ... 共 N 张表 ``` #### ✅ 插入路由逻辑(Python 示例): ```python import hashlib def get_table_index(user_id, shard_count=3): return user_id % shard_count def insert_order(user_id, amount): table_idx = get_table_index(user_id) sql = f""" INSERT INTO order_{table_idx} (user_id, amount, create_time) VALUES ({user_id}, {amount}, NOW()) """ # execute(sql) print(sql) # 示例调用 insert_order(1001, 99.5) # 路由到 order_1 insert_order(1002, 88.0) # 路由到 order_2 ``` > 🔍 注意:应用层需维护路由逻辑,或使用中间件(如 MyCat、ShardingSphere)。 --- ### 三、垂直分库(Vertical Database Splitting) #### ✅ 定义: 按业务模块将不同的表分配到不同的数据库中。 #### ✅ 目的: - 隔离业务,降低耦合 - 减轻单库压力 - 提升安全性与可维护性 #### ✅ 示例: 原本所有表在一个库 `db_all` 中: - user 表 - order 表 - product 表 - payment 表 拆分为: - `db_user`: 存放用户相关表 - `db_order`: 存放订单相关表 - `db_product`: 存放商品相关表 - `db_payment`: 存放支付相关表 #### ✅ 连接配置示例(Python + SQLAlchemy): ```python from sqlalchemy import create_engine engines = { 'user': create_engine('mysql+pymysql://user:pass@localhost/db_user'), 'order': create_engine('mysql+pymysql://user:pass@localhost/db_order'), 'product': create_engine('mysql+pymysql://user:pass@localhost/db_product'), } # 使用 conn = engines['user'].connect() result = conn.execute("SELECT * FROM user_core WHERE id = 1") ``` > ⚠️ 跨库关联困难,通常避免跨库 JOIN。 --- ### 四、水平分库(Horizontal Database Sharding) #### ✅ 定义: 将同一张表的数据按某种规则(如用户 ID、地理位置)分布到多个数据库实例中。 #### ✅ 目的: - 极大提升系统扩展能力 - 实现分布式架构 - 支持海量数据存储与高并发 #### ✅ 示例: 有 4 个数据库实例:`shard_0`, `shard_1`, `shard_2`, `shard_3` 对 `user` 表进行水平分库,按 `user_id % 4` 路由。 ```python def get_shard_engine(user_id): shard_id = user_id % 4 connection_strings = [ 'mysql+pymysql://u:p@host1/shard_0', 'mysql+pymysql://u:p@host2/shard_1', 'mysql+pymysql://u:p@host3/shard_2', 'mysql+pymysql://u:p@host4/shard_3', ] engine = create_engine(connection_strings[shard_id]) return engine # 插入用户数据 def insert_user(user_id, name): engine = get_shard_engine(user_id) with engine.connect() as conn: conn.execute( "INSERT INTO user (id, name) VALUES (%s, %s)", (user_id, name) ) ``` > 🌐 水平分库常配合水平分表一起使用(称为“分片”),构成完整的分库分表方案。 --- ### 各种分法对比总结: | 类型 | 拆分维度 | 典型场景 | 优点 | 缺点 | |------|----------|---------|------|------| | 垂直分表 | 列(字段) | 宽表拆解 | 减少 I/O,提升查询效率 | 需要 JOIN,开发复杂 | | 水平分表 | 行(数据记录) | 单表过大 | 分散负载,提高性能 | 跨表查询难,需路由 | | 垂直分库 | 业务模块 | 微服务拆分 | 业务隔离,易于维护 | 跨库事务难处理 | | 水平分库 | 数据行 + 多库 | 海量数据、高并发 | 极致扩展性 | 架构复杂,运维成本高 | --- ### 推荐工具与框架: - **Apache ShardingSphere**(支持分库分表透明化) - **MyCat**(数据库中间件) - **Vitess**(MySQL 的 Kubernetes 级别分片系统) - **TiDB**(兼容 MySQL 协议的分布式数据库,自动分片) --- ### 注意事项: 1. **全局唯一 ID**:分表后自增主键冲突 → 使用 Snowflake、UUID、Redis ID 生成器。 2. **跨分片查询**:尽量避免;可用搜索引擎(ES)做聚合查询。 3. **事务一致性**:跨库事务需用分布式事务(如 Seata、XA、TCC)。 4. **扩容问题**:取模分片扩容麻烦 → 改用一致性哈希或范围分片。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值