MySQL 千万级大数据表分区管理

在处理海量数据(如车辆定位、订单记录等)时,单表数据量突破千万后,查询和维护会变得极其困难。本文总结了基于 Range 分区 的全生命周期管理方案,涵盖了从建表优化到高效清理的核心操作。

1. 建立分区表 (核心设计)

在建表时,最关键的是主键必须包含分区字段。针对不同的时间字段类型,有两种标准的建表方式:

A. 针对 DATETIME 类型 (推荐使用 TO_DAYS)

适用于公交定位等数据,兼容性最强。

CREATE TABLE `positioning_data` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `cph` varchar(20) DEFAULT NULL,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 自动记录入库时间
  PRIMARY KEY (`id`, `created_at`) -- 必须包含分区字段
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
PARTITION BY RANGE (TO_DAYS(`created_at`)) (
  PARTITION p20251227 VALUES LESS THAN (TO_DAYS('2025-12-28')),
  PARTITION p20251228 VALUES LESS THAN (TO_DAYS('2025-12-29')),
  PARTITION p_future VALUES LESS THAN MAXVALUE -- 兜底分区,防止溢出
);

B. 针对 TIMESTAMP 类型 (推荐使用 UNIX_TIMESTAMP)

适用于订单、日志等表。

CREATE TABLE `order_cancel` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `received_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`, `received_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
PARTITION BY RANGE (UNIX_TIMESTAMP(`received_at`)) (
  PARTITION p20251227 VALUES LESS THAN (UNIX_TIMESTAMP('2025-12-28 00:00:00')),
  PARTITION p20251228 VALUES LESS THAN (UNIX_TIMESTAMP('2025-12-29 00:00:00')),
  PARTITION p_future VALUES LESS THAN MAXVALUE
);

2. 查看分区状态

执行分区后,我们需要实时监控各个“抽屉”里的数据量和物理占用。

-- 查看指定表的分区分布、行数及物理大小
SELECT 
    PARTITION_NAME AS '分区名',
    PARTITION_DESCRIPTION AS '分区范围值', 
    TABLE_ROWS AS '预估行数',
    ROUND(DATA_LENGTH / 1024 / 1024, 2) AS '数据大小(MB)',
    ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS '索引大小(MB)'
FROM information_schema.PARTITIONS
WHERE TABLE_NAME = 'positioning_data' 
  AND TABLE_SCHEMA = 'cleaned_data';

3. 分区数据的精准清理

这是分区表最大的优势:秒级清理,不锁全表,不占 Undo Log

A. 清空分区数据 (保留结构)

如果你想清理某一天的数据,但希望保留分区以便新数据继续进入。

ALTER TABLE positioning_data TRUNCATE PARTITION p20251227;

B. 物理删除分区 (连同结构)

如果你确定某天的数据永远不再需要,可以直接丢弃。

ALTER TABLE positioning_data DROP PARTITION p20251227;

4. 全局数据统计

当数据库中存在多个千万级大表时,可以使用子查询快速横向对比。

SELECT
  (SELECT COUNT(*) FROM tsms_position_vehicle) AS tsms_position_vehicle_count,
  (SELECT COUNT(*) FROM positioning_data) AS positioning_data_count,
  (SELECT COUNT(*) FROM order_cancel) AS order_cancel_count;

5. 彻底重置表 (Truncate Table)

如果需要清空整个表(包括所有分区数据)并重置自增 ID,TRUNCATEDROP 更轻量。

TRUNCATE TABLE positioning_data;
TRUNCATE TABLE order_cancel;

6. 避坑指南与经验总结

  1. 主键限制:MySQL 要求分区字段必须是主键的一部分,否则无法创建分区。
  2. 锁竞争问题:如果在删除表(DROP)时遇到 Unknown table 或一直卡住,通常是因为后台有类似 Hadoop 的采集程序正在进行高频写入,产生了元数据锁(Metadata Lock)。操作前应先停掉写入源
  3. 自动计时:使用 DEFAULT CURRENT_TIMESTAMP 字段作为分区依据,可以实现数据入库时自动归位,无需修改业务代码。
  4. 粒度选择:对于千万级数据,建议按“天”分区;对于亿级数据,才考虑按“小时”分区。分区过多会增加元数据管理的开销。

本文基于 2025 年 12 月车联网大数据处理实战经验整理。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇