MySQL分区(Partition)实战指南

分区优势

  1. 管理大表:当单表数据达到数亿行、几十 GB 以上时,用分区能把数据分散到多个逻辑/物理单元,易维护。

  2. 提高查询性能(在能走分区剪枝时):针对分区键的查询可只扫描少数分区(Partition Pruning),显著减少 IO。

  3. 快速归档/删除 :删除旧数据可以通过 DROP PARTITION 或 EXCHANGE PARTITION 实现"常数时间"删除,而不用 DELETE 全表扫描。

  4. 并行化/并发:某些存储引擎/环境下分区可促进并行 I/O(不是万能的)。

  5. 局部重建/维护 :可以对单个分区做 OPTIMIZE、备份、恢复,降低维护成本。

分区示例

sql 复制代码
-- 创建订单表,并按 created_at 字段按年份分区
CREATE TABLE orders (
  id BIGINT NOT NULL AUTO_INCREMENT,
  user_id INT NOT NULL,
  created_at DATE NOT NULL,
  amount DECIMAL(10,2),
  -- 必须包含分区列在主键中
  PRIMARY KEY (id, created_at) 
)
PARTITION BY RANGE COLUMNS(created_at) (
  PARTITION p2022 VALUES LESS THAN ('2023-01-01'),
  PARTITION p2023 VALUES LESS THAN ('2024-01-01')
);

-- 插入数据
INSERT INTO orders (user_id, created_at, amount) 
VALUES 
  (1, '2022-03-10', 100.00),
  (2, '2022-06-15', 250.50),
  (3, '2023-01-22', 120.75),
  (4, '2023-08-09', 350.25);

-- 查看表信息
SHOW CREATE TABLE orders

-- 为 2025 年的数据添加分区
-- LESS THAN = 分区接收"所有小于某个值"的数据
ALTER TABLE orders 
ADD PARTITION (PARTITION p2025 VALUES LESS THAN ('2026-01-01'));

-- 插入 2025 年的数据(如果2025年的分区还没有创建好,数据不能进入特定的分区)
-- 添加会报错 ERROR 1526 (HY000): Table has no partition for value ...
INSERT INTO orders (user_id, created_at, amount)
VALUES 
  (6, '2025-02-10', 450.00),
  (7, '2025-03-20', 300.00);
  
  -- 删除 2022 年的分区(删除2022年分区的时候,2022年的数据也会被删除)
ALTER TABLE orders 
DROP PARTITION p2022;

-- 查询 2023 年的数据
SELECT * FROM orders 
WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31';

Java实现分区

1.创建一个定时器(每天定时查询分区是否存在,不存在则创建分区)

java 复制代码
    @XxlJob("AUTO_CREATE_PARTITION")
    public void autoCreatePartition() {
        businessUserRecallReachService.autoCreatePartition();
    }

2.查询分区是否存在

java 复制代码
select partition_name from information_schema.partitions
where table_name='business_user_recall_reach_record' and partition_name=#{partitionName} limit 1

3.不存在,创建分区

java 复制代码
ALTER TABLE business_user_recall_reach_record add PARTITION (PARTITION ${partitionName}  VALUES LESS THAN (${partitionDate}))

代码:

java 复制代码
    /**
     * 初始化按月分区
     *
     * @param model 数据模型
     */
    private void initializeMonthPartition(Class<?> model) {
        LocalDate now = LocalDate.now();
        String name = "p" + DateUtils.month2number(now.plusMonths(1));
        String value = now.plusMonths(2).format(DateTimeFormatter.ofPattern("yyyy-MM-01"));
        String table = SQLUtils.unquote(TableInfoHelper.getTableInfo(model).getTableName());
        if (!this.baseMapper.hasPartition(table, name)) {
            this.baseMapper.addPartition(table, name, value);
        }
    }
相关推荐
ly76894 小时前
PostgreSQL 执行计划深读:从 EXPLAIN 输出到代价模型驱动的 SQL 改写
数据库·sql·postgresql·explain·执行计划·代价模型
Python自动化直播5 小时前
自动化笔记:素材管理、命名、轮换的几条土办法
linux·运维·数据库
xiaomuzuirenzhen5 小时前
2027校招ERP实施顾问:大数据管理与应用专业如何用SQL、BI证明业务能力
大数据·数据库
eleven_4u5 小时前
MySQL深分页如何处理
mysql
底层玩家老张5 小时前
从副本集到分片:百亿级文档数据的KES架构边界
数据库·分布式架构·分片·架构选型·文档数据库
ss2735 小时前
AI时代首先数据库-PostgreSQL实战笔记 | 16 PostgreSQL子查询与嵌套查询(下)
数据库·笔记·postgresql
川石课堂软件测试5 小时前
涨薪技术|0到1学会性能测试第8课-Analysis分析图
服务器·数据库·python·sql·jmeter·mysql·容器
SelectDB技术团队5 小时前
云数仓成本结构拆解:五层计费模型与 Apache Doris 托管形态对照
大数据·数据库·elk·全文检索·snowflake
我命由我123456 小时前
SQL 检测脚本
java·数据库·sql·功能测试·单元测试·压力测试·可用性测试
Zenova EdgeOS6 小时前
工业网关数据全链路加密实战:从传输、静态数据到密钥轮
数据库·oracle·边缘计算·工业网关