Mysql--运维篇--库表分离(垂直分库,水平分库,垂直分表,水平分表)

在处理大规模数据和高并发访问时,数据库的分库和分表是两种常见的优化策略。它们通过将数据分散到多个数据库或表中,来提高性能、可扩展性和管理效率。为了更精细地应对不同的场景,分库和分表可以进一步细分为垂直分库/分表和水平分库/分表。

一、分库(Database Sharding)

分库是指将一个大的数据库拆分成多个独立的数据库实例,每个数据库实例负责存储一部分数据。这些数据库实例可以分布在不同的服务器上,以实现负载均衡和高可用性。

目的:

  • 提高性能:通过将数据分散到多个数据库实例中,减少了单个数据库的压力,提升了查询和写入的性能。
  • 提升可扩展性:随着数据量的增长,可以通过增加更多的数据库实例来扩展系统。
  • 增强容错能力:即使某个数据库实例发生故障,其他实例仍然可以继续提供服务。

适用场景:

  • 当单个数据库实例无法承受巨大的数据量或高并发访问时。
  • 当需要支持分布式架构,确保系统的高可用性和容错能力。

二、分表(Table Partitioning)

分表是指将一个大表拆分成多个小表,每个小表存储原表的一部分数据。分表可以在同一个数据库内进行,也可以跨多个数据库实例进行。

目的:

  • 减少单表的行数或列数,降低查询时的扫描范围,提升查询性能。
  • 优化索引和缓存命中率,减少不必要的I/O操作。
  • 简化维护,例如备份、恢复和清理操作。

适用场景:

  • 当单个表的行数或列数过多,导致查询性能下降时。
  • 当某些字段的访问频率远高于其他字段,或者某些字段占用大量空间但不经常被查询时。

三、垂直分库与垂直分表

1、垂直分库(Vertical Database Sharding)

垂直分库是指将不同的表或表中的不同字段分配到不同的数据库实例中。每个数据库实例负责存储特定类型的表或字段。

原理:

  • 按功能或业务模块划分:将不同的业务模块(如用户信息、订单信息、商品信息等)存储在不同的数据库中。
  • 按字段划分:将一个表中的不同字段拆分到不同的数据库中,通常通过主键或其他唯一标识符关联。

优点:

  • 减少单个数据库的复杂性:每个数据库只负责特定的业务逻辑,降低了复杂度。
  • 优化查询性能:减少了每次查询时需要读取的数据量,提升了查询速度。
  • 简化索引管理:可以为每个数据库创建更合适的索引,避免不必要的索引维护开销。

缺点:

  • 增加了应用程序的复杂性:需要在应用层面对多个数据库进行管理和路由。
  • JOIN操作复杂:当需要从多个数据库中获取完整的信息时,必须执行跨库JOIN操作,这可能会增加查询的复杂性和执行时间。

示例:

假设你有一个电子商务平台,可以将用户信息、订单信息和商品信息分别存储在三个不同的数据库中。

  • db_users:存储用户信息表users。
  • db_orders:存储订单信息表orders。
  • db_products:存储商品信息表products。

2、垂直分表(Vertical Table Partitioning)

垂直分表是指将一个大表按照列(字段)进行拆分,将不同类型的字段分配到不同的表中。每个新表包含原表的一部分列,并且这些表之间通常通过主键或其他唯一标识符关联。

原理:

  • 按字段使用频率划分:将常用的字段和不常用的字段分开,减少每次查询时需要读取的数据量。
  • 按字段类型划分:将不同类型的数据(如字符串、数值、BLOB等)分开存储,优化存储和查询性能。

优点:

  • 提升查询性能:减少了每次查询时需要扫描的列数,降低了I/O开销。
  • 优化缓存命中率:较小的表更容易适应内存缓存,减少了磁盘I/O操作。
  • 简化索引管理:可以为每个表创建更合适的索引,避免不必要的索引维护开销。

缺点:

  • 增加了应用程序的复杂性:需要在应用层面对多个表进行管理和路由。
  • JOIN操作复杂:当需要从多个表中获取完整的信息时,必须执行JOIN操作,这可能会增加查询的复杂性和执行时间。

示例:

假设有一个用户表 users,包含以下字段:

java 复制代码
- user_id
- username
- password
- email
- profile_picture (BLOB)
- last_login
- created_at

垂直分表后,拆分为两个表:

java 复制代码
-- 用户基本信息表
CREATE TABLE users_basic (
    user_id INT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(255),
    email VARCHAR(100)
);

-- 用户附加信息表
CREATE TABLE users_extra (
    user_id INT PRIMARY KEY,
    profile_picture BLOB,
    last_login DATETIME,
    created_at DATETIME
);

四、水平分库与水平分表

1、水平分库(Horizontal Database Sharding)

水平分库是指将一个大的数据库拆分成多个数据库实例,每个数据库实例存储原数据库中的一部分行(记录)。通常根据某个字段(如用户ID、订单ID等)进行分片,确保相同类型的数据分散到不同的数据库中。

原理:

  • 按行划分:将表中的行根据某个字段(称为分片键或Shard Key)分配到不同的数据库实例中。
  • 分布式架构:每个数据库实例可以分布在不同的服务器上,实现负载均衡和高可用性。

优点:

  • 提升查询性能:减少了单个数据库的行数,降低了查询时的扫描范围,提升了查询速度。
  • 提高可扩展性:随着数据量的增长,可以通过增加更多的数据库实例来扩展系统。
  • 增强容错能力:即使某个数据库实例发生故障,其他实例仍然可以继续提供服务。

缺点:

  • 复杂的查询逻辑:跨分片的查询(如全局查询)可能会变得复杂,因为需要从多个数据库中获取数据并合并结果。
  • 数据一致性挑战:确保所有分片之间的数据一致性和同步可能是一个挑战,特别是在分布式环境中。
  • 分片键选择困难:选择合适的分片键非常重要,不恰当的选择可能导致数据分布不均或查询性能下降。

示例:

假设你有一个订单表orders,可以根据user_id将订单分散到多个数据库中。假设我们有4个数据库实例,可以使用哈希分片策略:

shard_id = HASH(user_id) % 4
然后,订单数据会根据user_id的哈希值分配到不同的数据库实例中:

  • db_orders_0:存储user_id的哈希值为0的订单。
  • db_orders_1:存储user_id的哈希值为1的订单。
  • db_orders_2:存储user_id的哈希值为2的订单。
  • db_orders_3:存储user_id的哈希值为3的订单。

2、水平分表(Horizontal Table Partitioning)

水平分表是指将一个大表按照行(记录)进行拆分,将不同的行分配到不同的表中。每个新表包含原表的全部列,但只包含部分行。水平分表可以通过多种方式进行划分,常见的有基于范围、哈希、列表等方式。

原理:

  • 按行划分:将表中的行根据某个字段(称为分片键或Shard Key)分配到不同的表中。
  • 分布式架构:每个表可以分布在不同的数据库实例中,实现负载均衡和高可用性。

优点:

  • 提升查询性能:减少了单个表的行数,降低了查询时的扫描范围,提升了查询速度。
  • 提高可扩展性:随着数据量的增长,可以通过增加更多的表来扩展系统。
  • 增强容错能力:即使某个表发生故障,其他表仍然可以继续提供服务。

缺点:

  • 复杂的查询逻辑:跨分片的查询(如全局查询)可能会变得复杂,因为需要从多个表中获取数据并合并结果。
  • 数据一致性挑战:确保所有分片之间的数据一致性和同步可能是一个挑战,特别是在分布式环境中。
  • 分片键选择困难:选择合适的分片键非常重要,不恰当的选择可能导致数据分布不均或查询性能下降。

示例:

假设我们有一个订单表orders,可以根据user_id对订单进行水平分片。假设我们有4个分片表,可以使用哈希分片策略:

shard_id = HASH(user_id) % 4
水平分表,可以创建4个分片表:

-- 分片 0

java 复制代码
CREATE TABLE orders_shard_0 (
    order_id INT PRIMARY KEY,
    user_id INT,
    product_id INT,
    order_date DATETIME,
    total_amount DECIMAL(10, 2)
);

-- 分片 1

java 复制代码
CREATE TABLE orders_shard_1 (
    order_id INT PRIMARY KEY,
    user_id INT,
    product_id INT,
    order_date DATETIME,
    total_amount DECIMAL(10, 2)
);

-- 分片 2

java 复制代码
CREATE TABLE orders_shard_2 (
    order_id INT PRIMARY KEY,
    user_id INT,
    product_id INT,
    order_date DATETIME,
    total_amount DECIMAL(10, 2)
);

-- 分片 3

java 复制代码
CREATE TABLE orders_shard_3 (
    order_id INT PRIMARY KEY,
    user_id INT,
    product_id INT,
    order_date DATETIME,
    total_amount DECIMAL(10, 2)
);

在插入或查询订单时,应用程序需要根据user_id计算出对应的shard_id,并将操作路由到相应的分片表中。

五、垂直分库与水平分库、垂直分表与水平分表的区别

六、垂直分库/分表与水平分库/分表的结合

在实际应用中,垂直分库/分表和水平分库/分表并不是互斥的,而是可以结合使用。例如,你可以先对表进行垂直分库,将不同的字段拆分到不同的表中,然后再对每个表进行水平分表,以进一步提高性能和可扩展性。

示例:

假设我们有一个电子商务平台,用户表users和订单表orders都非常大。我们可以先对users表进行垂直分表,将用户的基本信息和附加信息分开,然后再对orders表进行水平分表,根据user_id将订单分散到多个分片中。
垂直分表:

java 复制代码
-- 用户基本信息表
CREATE TABLE users_basic (
    user_id INT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(255),
    email VARCHAR(100)
);
-- 用户附加信息表
CREATE TABLE users_extra (
    user_id INT PRIMARY KEY,
    profile_picture BLOB,
    last_login DATETIME,
    created_at DATETIME
);

水平分表:

java 复制代码
CREATE TABLE orders_shard_0 (
    order_id INT PRIMARY KEY,
    user_id INT,
    product_id INT,
    order_date DATETIME,
    total_amount DECIMAL(10, 2)
);

CREATE TABLE orders_shard_1 (
    order_id INT PRIMARY KEY,
    user_id INT,
    product_id INT,
    order_date DATETIME,
    total_amount DECIMAL(10, 2)
);

-- 其他分片...

通过这种方式,我们可以同时利用垂直分表和水平分表的优势,既减少了单表的宽度,又分散了数据的行数,从而提高了整体性能和可扩展性。

七、总结

  • 分库是指将一个大的数据库拆分成多个独立的数据库实例,适用于需要分布式架构和高可用性的场景。
  • 分表是指将一个大表拆分成多个小表,适用于需要减少单表行数或列数的场景。
  • 垂直分库/分表是按列或表的功能进行划分,适用于字段较多且某些字段不常用的情况。
  • 水平分库/分表是按行进行划分,适用于数据量大、并发访问高的场景。
  • 两者结合 可以在更大规模的应用中提供更好的性能和可扩展性。

快速记忆:

分库是把表或者数据分布到不同的数据库上,减轻数据库压力。

分表是把表结构或者表数据拆分到不同的表上,减轻数据库压力。

垂直,一定是改变了结构(如数据库表量减少,或表的字段减少)。

水平,把数据分开(如根据分片分到不同数据库上,或分布到同一个库的不同分片表上)。

乘风破浪会有时,直挂云帆济沧海!!!

相关推荐
肉三9 分钟前
从 PostgreSQL 中挽救损坏的表
数据库·postgresql·数据恢复
NuyoahC2 小时前
MySQL 表的内连和外连
数据库·mysql
KeyPan3 小时前
【Ubuntu与Linux操作系统:十、C/C++编程】
linux·运维·服务器·c语言·c++·算法·ubuntu
后端研发Marion3 小时前
【DB-GPT】开启数据库交互新篇章的技术探索与实践
数据库·gpt
陌上花开缓缓归以4 小时前
linux 内核OOM问题定位-SLAB_DEBUG
linux·运维·服务器
努力的小T4 小时前
Linux 搭建 Docker 私有化仓库 Harbor 教程
linux·运维·服务器·docker·云原生·容器·云计算
hao_wujing4 小时前
使用 Linux tracepoint、perf 和 eBPF 跟踪数据包
linux·运维·php
2401_884810744 小时前
MySQL视图笔记
数据库·笔记·mysql
名为逗比4 小时前
从CentOS到龙蜥:企业级Linux迁移实践记录(龙蜥开局)
linux·运维·centos
小诸葛的博客5 小时前
docker run一个镜像如何指定最大可使用的内存大小、cpu大小
运维·docker·容器