Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL数据库水平、垂直、分区表

MySQL实现数据库分表(水平、垂直、分区表)详细操作步骤

作者:繁星蓝雨

MySQL分区表是一种将大表数据按特定规则拆分成多个独立存储单元的技术,能有效提升大数据量下的查询性能和管理效率,这篇文章主要介绍了MySQL实现数据库分表(水平、垂直、分区表)详细操作的相关资料,需要的朋友可以参考下

0 背景

因为数据库库的表数据量过大以及字段过多,产生了分表的想法。搜索网上资料后,得知有三种分表方式,最终结合其中的方式,实现了最终的分表效果。

1 理论

1.1 定义与区别

水平分表(水平拆分/水平分片)

垂直分表(垂直拆分/垂直分片)

分区表(分区)

1.2 详细对比

特性水平分表垂直分表分区表
拆分维度按行(记录)按列(字段)按规则(行或列)
表结构拆分后结构相同拆分后结构不同逻辑结构相同,物理分离
数据分布不同表存储同类型的不同记录不同表存储不同类型的字段物理上分离,逻辑上统一
对应用层影响需要应用层处理跨表查询需要应用层处理多表查询通常对应用层透明
适用场景单表数据量过大(千万级+)表字段过多、存在大字段数据量大、需高效管理
优点降低单表压力,提高扩展性降低单表字段数量,提升查询效率提升性能,简化数据管理
缺点复杂性增加,事务管理复杂跨表查询复杂,数据冗余实施复杂,内存使用可能增加
与分片关系水平分片的一种实现方式垂直分片的一种实现方式数据分片的一种实现方式

2 实践

2.1 水平分表

将一张表按行拆分成多张结构相同的表,解决单表数据量过大的问题。

2.1.1 按哈希取模分表

  1. 创建表;
-- 创建4个分表(实际应用中可以使用程序动态创建)
CREATE TABLE orders_0 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;

CREATE TABLE orders_1 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;

CREATE TABLE orders_2 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;

CREATE TABLE orders_3 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;
  1. 插入数据(因为user_id12345 % 4 = 1,故插入到orders_1表中);
- 插入数据示例:user_id=12345会插入到orders_1表(12345 % 4 = 1)
INSERT INTO orders_1 (order_id, user_id, amount, create_time) 
VALUES (1001, 12345, 200.00, NOW());

2.1.2 按时间范围分表

1.创建表;

-- 创建按月份分表
CREATE TABLE orders_202301 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;

CREATE TABLE orders_202302 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;
  1. 插入数据;
-- 创建按月份分表
CREATE TABLE orders_202301 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;

CREATE TABLE orders_202302 (
    order_id INT PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
) ENGINE=InnoDB;

2.2 垂直分表

垂直分表是将一张表按列拆分成多张表,解决表结构过宽的问题。

  1. 假设有如下的原始表:
-- 原始表(包含大字段和常用字段)
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100),
    address VARCHAR(255),
    phone VARCHAR(20),
    created_at DATETIME,
    updated_at DATETIME,
    profile TEXT  -- 大字段,可能会影响查询性能
) ENGINE=InnoDB;
  1. 垂直分表后的结构;
-- 基本信息表(高频查询字段)
CREATE TABLE users_basic (
    user_id INT PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100),
    created_at DATETIME,
    updated_at DATETIME
) ENGINE=InnoDB;

-- 详情信息表(包含大字段和不常用字段)
CREATE TABLE users_detail (
    user_id INT PRIMARY KEY,
    address VARCHAR(255),
    phone VARCHAR(20),
    profile TEXT
) ENGINE=InnoDB;
  1. 插入数据;
-- 插入数据示例
INSERT INTO users_basic (user_id, username, email, created_at, updated_at)
VALUES (1, 'user123', 'user123@example.com', NOW(), NOW());

INSERT INTO users_detail (user_id, address, phone, profile)
VALUES (1, '123 Main St, City, Country', '123-456-7890', 'This is a user profile');

2.3 分区表

分区表是将一张表在物理上分成多个分区,但逻辑上仍是一张表,由MySQL内部管理。

2.3.1 按范围分区(按年份)

  1. 创建表;
-- 创建按年份范围分区的表
CREATE TABLE orders (
    order_id INT ,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME,
		PRIMARY KEY(order_id, create_time)
) ENGINE=InnoDB
PARTITION BY RANGE (YEAR(create_time)) (
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p2025 VALUES LESS THAN (2026)
);

MySQL要求主键必须包含分区键(即分区表达式中使用的列)

  1. 插入数据;
-- 插入数据示例:2023年的数据会自动插入到p2023分区
INSERT INTO orders (order_id, user_id, amount, create_time)
VALUES (1001, 12345, 200.00, '2023-01-15 10:30:00');
  1. 查询数据;
-- 查询2023年的数据(优化器会只扫描p2023分区)
SELECT * FROM orders WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01';

2.3.2 按范围分区(按年份)

  1. 创建表;
-- 创建按user_id哈希分区的表
CREATE TABLE orders_4 (
    order_id INT ,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME,
		PRIMARY KEY (order_id, user_id)
) ENGINE=InnoDB
PARTITION BY HASH (user_id)
PARTITIONS 4;
  1. 插入数据;
-- 插入数据示例:user_id=12345会自动分配到分区1(12345 % 4 = 1)
INSERT INTO orders_4 (order_id, user_id, amount, create_time)
VALUES (1001, 12345, 200.00, NOW());
  1. 查询数据
-- 查询示例(需包含分区键,才能进行分区裁剪)
SELECT * FROM orders_4 WHERE user_id = 12345;

2.3.3

  1. 创建表;
CREATE TABLE orders_5 (
    order_id INT ,
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME,
    region VARCHAR(20),
		PRIMARY KEY (order_id, region)
) ENGINE=InnoDB
PARTITION BY LIST  COLUMNS(region) (
    PARTITION asia VALUES IN ('China', 'Japan', 'Korea'),
    PARTITION europe VALUES IN ('France', 'Germany', 'Italy'),
    PARTITION america VALUES IN ('USA', 'Canada', 'Mexico')
);
特性LIST (expr)LIST COLUMNS (col)
支持的数据类型仅整数表达式字符串、日期、整数等任意列类型
分区值格式必须是整数(如 VALUES IN (1,2,3)可直接使用字面量(如 VALUES IN ('China','USA')
MySQL 版本要求所有版本MySQL 5.5+(推荐 5.7+)
适用场景按整数ID分区按字符串/日期等业务字段分区
  1. 插入数据;
INSERT INTO orders_5 (order_id, user_id, amount, create_time, region)
VALUES (1001, 12345, 200.00, NOW(), 'China');
  1. 查询数据;
SELECT * FROM orders_5 WHERE region = 'China';

3. 适用场景

3.1 水平分表适用场景

3.2 垂直分表适用场景

3.3 分区表适用场景

3.4 区分水平和分区表的使用

优先考虑分区表:
1,当数据量达到百万级,但不需要跨表查询
2,当查询主要基于分区键(如时间范围)
3,当希望简化应用层逻辑,减少开发复杂度

考虑水平分表:
1,当需要更高扩展性,需要跨数据库分片
2,当数据分布不均,分区表无法满足需求
3,当需要结合分库策略进行更高级别的扩展

4. 组合使用

在实际业务中,水平分表和垂直分表通常结合使用,形成"先垂直后水平"或"先水平后垂直"的拆分方案:

  1. 先垂直后水平

    • 先按业务模块对单库单表进行垂直拆分,降低业务耦合度
    • 再对垂直拆分后数据量较大的表进行水平拆分,突破数据量限制
    • 例如:电商系统的"订单表"垂直拆分为"订单基本表"、“订单支付表”、“订单物流表”,再对"订单基本表"按"下单时间+用户ID哈希"进行水平拆分
  2. 先水平后垂直

    • 对数据量极大但字段结构复杂的表,先按行进行水平拆分
    • 再对每个水平分表进行垂直拆分,优化单表查询性能
    • 例如:社交平台的"用户动态表"先按"用户ID哈希"水平拆分为多个分表,再对每个分表垂直拆分为"动态基本信息表"和"动态内容(大字段)表"

5. 总结

在实际应用中,应根据具体业务需求和数据特点选择合适的分表策略,必要时结合使用水平分表和垂直分表,以达到最佳的数据库性能和可维护性。

到此这篇关于MySQL实现数据库分表(水平、垂直、分区表)详细操作步骤的文章就介绍到这了,更多相关MySQL数据库水平、垂直、分区表内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文