MySQL 分库分表策略

小飞兽 数据库 189 次阅读 2026-05-09

概述

随着业务规模的增长,单库单表的架构会遇到性能瓶颈。分库分表(Sharding)是一种将数据分散到多个数据库或数据表中的水平扩展策略,通过将读写压力分散到多个存储节点,可以有效应对高并发和大数据量的场景。本文系统介绍分库分表的常见策略、路由算法以及实际应用中的注意事项。

基础语法

分库分表的核心思想是将原本存储在单库单表中的数据,按照某种规则分散到多个库或多张表中。根据拆分维度,分为垂直拆分(按业务字段拆分)和水平拆分(按数据行拆分)。水平拆分解决了单表数据量过大的问题,垂直拆分则解决了单库表过多或单表字段过多的问题。

    • 水平分表:将一张大表按行拆分多张结构相同的子表。
    • 水平分库:将数据分散到多个数据库实例中,每个库结构相同但数据不重叠。
    • 垂直分表:将大表的字段按冷热分离。
    • 垂直分库:按业务模块将表分散到不同数据库。

    路由算法决定了数据应该落到哪个分片中,常见的有取模路由(ID % n)、范围路由(ID 区间)和一致性哈希(Consistent Hash)。

    完整代码示例+注释

    -- === 分表策略:按用户 ID 取模分表 ===
    -- 假设分 4 张表:user_0, user_1, user_2, user_3
    

    -- 路由算法示例(应用层实现)
    function get_table_name(user_id):
    table_index = user_id % 4
    return "user_" + table_index

    -- 分表后的查询
    SELECT * FROM user_{user_id % 4} WHERE id = ?

    -- === 分库策略:按业务 ID 取模 ===
    -- 分 2 个库:db_0, db_1

    -- === 一致性哈希分片(应对扩容) ===
    -- 节点分布在 2^32 的哈希环上

    -- === MySQL 水平分表建表语句 ===
    CREATE TABLE orders_0 (
    id BIGINT PRIMARY KEY,
    user_id BIGINT NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_id (user_id),
    INDEX idx_created (created_at)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

    -- === 跨分片查询示例 ===
    CREATE TEMPORARY TABLE tmp_orders AS
    SELECT * FROM orders_0 WHERE created_at > '2024-01-01'
    UNION ALL
    SELECT * FROM orders_1 WHERE created_at > '2024-01-01'
    UNION ALL
    SELECT * FROM orders_2 WHERE created_at > '2024-01-01'
    UNION ALL
    SELECT * FROM orders_3 WHERE created_at > '2024-01-01';

    SELECT * FROM tmp_orders ORDER BY created_at DESC LIMIT 20 OFFSET 0;
    DROP TEMPORARY TABLE tmp_orders;

    运行效果

    实施分库分表后,原本单表千万级的数据被分散到 4 张子表中,每张表的数据量降至百万级别,查询性能显著提升。使用 UNION ALL 合并多分片结果时,由于需要扫描所有分片,跨分片查询的性能会比单分片查询差,应尽量将查询条件收敛到单个分片内。

    常见问题

    Q1:分库分表后如何实现分页查询
    常见解法是:允许查询结果的近似分页;使用ElasticSearch等搜索引擎承接分页查询;或者维护一张汇总表记录各分片的数据范围。

    Q2:分片键如何选择
    分片键应选择查询最频繁且数据分布均匀的字段。用户ID是最常见的分片键。

    Q3:分库分表后主键ID如何生成
    解决方案有:分布式ID生成器(如Twitter Snowflake);在应用层维护一个全局ID发号器;使用UUID。

    Q4:如何平滑扩容而不停服
    双写方案:先新增分片,双写新旧分片,然后后台迁移历史数据,校验一致后切换读流量,最后下线旧分片。

    延伸阅读

    • ShardingSphere:Apache 旗下的分布式数据库中间件生态,支持数据分片、读写分离、分布式事务等能力。
    • MyCat:另一款成熟的 MySQL 分库分表中间件,支持跨分片查询、SQL 路由等功能。
    • 美团 Leaf 分布式ID生成器:https://github.com/Meituan-Dianping/Leaf
  • 《数据密集型应用系统设计》:涵盖了分布式存储、副本一致性、分片策略等核心概念。