TDSQL创建分区表

最近因TDSQL存放物联感知数据量增长较快,因此为提升性能,使用分区表。

建表

sql 复制代码
DROP TABLE `data_iot2`;
CREATE TABLE `data_iot2` (
  `id` bigint(20) NOT NULL COMMENT '分布式ID',
  `device_id` varchar(64) NOT NULL COMMENT '设备唯一标识',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '数据创建时间',
  `metric_name` varchar(128) NOT NULL,
  `metric_value` decimal(18,4) NOT NULL,
  `unit` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`, `device_id`, `create_time`),
  KEY `idx_data_iot2_device_id_create_time` (`device_id`, `create_time`),
  KEY `idx_data_iot2_create_time` (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY RANGE (TO_DAYS(`create_time`)) (
    PARTITION p202601 VALUES LESS THAN (TO_DAYS('2026-02-01')),
    PARTITION p202602 VALUES LESS THAN (TO_DAYS('2026-03-01')),
    PARTITION p202603 VALUES LESS THAN (TO_DAYS('2026-04-01')),
    PARTITION p_max VALUES LESS THAN MAXVALUE
);

为何如此设计?

1、满足分区规则:分区键是 TO_DAYS(create_time),所以 create_time必须在主键中。

2、保证全局唯一性:id本身是分布式ID,理论上全局唯一。但MySQL的分区逻辑无法感知这一点,它要求主键能唯一标识整个表的每一行。通过将 id设为主键的第一列,我们确保了主键的唯一性。

3、包含查询键:device_id是高频查询条件,将其加入主键,可以让某些查询(如 WHERE device_id = ? AND create_time = ?)直接通过主键定位,速度极快。

潜在缺点:

主键过长:InnoDB的主键是聚集索引,其叶子节点存储了整行数据。一个过长的主键会增加索引占用的空间,并可能降低基于主键的插入和更新性能。不过,对于您的字段类型,这个长度尚可接受。

注意点

重要警告:在分区表中,类似WHERE create_time > '2026-02-10 10:00:00'这种查询的性能是灾难性的!因为它会导致MySQL的查询优化器无法有效进行分区裁剪(Partition Pruning),可能会变成全分区扫描,即扫描 p202601, p202602, p202603, p_max所有分区,性能极低。强烈建议避免使用此类查询,或者在业务上保证此类查询必须带上 device_id或其他能缩小范围的条件。

插入测试数据

sql 复制代码
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (1, '1', '2026-01-01 17:27:55', '1', 1.0000, '1');
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (2, '2', '2026-01-02 17:28:11', '2', 2.0000, '2');
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (3, '3', '2026-02-02 17:28:29', '3', 3.0000, '3');
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (4, '4', '2026-02-04 17:28:42', '4', 4.0000, '4');
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (5, '5', '2026-03-19 17:28:52', '5', 5.0000, '5');
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (6, '6', '2026-05-30 17:29:03', '6', 6.0000, '6');
INSERT INTO `test`.`data_iot2` (`id`, `device_id`, `create_time`, `metric_name`, `metric_value`, `unit`) VALUES (7, '7', '2026-06-09 18:02:44', '7', 7.0000, '7');

验证

1、执行以下查询计划

sql 复制代码
EXPLAIN SELECT * FROM `data_iot2` WHERE create_time > '2026-01-01' and create_time < '2026-02-01'

可以看到定位到了分区p202601上

2、执行以下查询计划

sql 复制代码
EXPLAIN SELECT * FROM `data_iot2` WHERE create_time = '2026-06-09 18:02:44'

由于没有p202606分区,因此定位了p_max分区,注意这里即使重新创建p202601分区,原有已经入库的数据也不会自动挪到新建的分区上

3、执行以下查询计划

sql 复制代码
EXPLAIN SELECT * FROM `data_iot2` WHERE create_time > '2026-06-09 18:02:44'

从查询计划看,可以看到查询了多个分区

其他

增加分区

sql 复制代码
ALTER TABLE `data_iot2`
REORGANIZE PARTITION p_max INTO (
    -- 1. 定义新的2026年4月分区
    PARTITION p202606 VALUES LESS THAN (TO_DAYS('2026-07-01')),
    -- 2. 重新定义p_max,作为新的"未来"分区
    PARTITION p_max VALUES LESS THAN MAXVALUE
);

查询表的所有分区

sql 复制代码
SELECT
    PARTITION_NAME,           -- 分区名 (如 p202310, p_max)
    PARTITION_ORDINAL_POSITION, -- 分区在表中的位置序号 (从1开始)
    TABLE_ROWS,               -- 分区中大约的行数 (注意:是估计值,非精确值!)
    PARTITION_DESCRIPTION,    -- 分区的定义描述 (如 VALUES LESS THAN (202311))
    NODEGROUP,                -- 节点组 (用于NDB集群,InnoDB表通常为空)
    TABLESPACE_NAME           -- 表空间名 (通常为空,除非使用了独立的表空间)
FROM
    INFORMATION_SCHEMA.PARTITIONS
WHERE
    TABLE_SCHEMA = 'test' -- 替换为您的数据库名
    AND TABLE_NAME = 'data_iot2';   -- 替换为您的表名
相关推荐
dys_Codemonkey7 小时前
如何在树莓派上用 VS Code 优雅直连内部的 Ubuntu 子系统/容器用来访问容器内的文件和代码?
linux·运维·ubuntu·树莓派
gameboy0317 小时前
从MySQL迁移到PostgreSQL的完整指南
数据库·mysql·postgresql
上海合宙LuatOS8 小时前
LuatOS核心库API——【 string】字符串操作
运维·服务器·物联网·junit·硬件工程·信息与通信·嵌入式实时数据库
RDCJM8 小时前
mysql表添加索引
数据库·mysql
徐子元竟然被占了!!8 小时前
Linux的cat
linux·运维·服务器
带娃的IT创业者8 小时前
WeClaw 离线消息队列实战:异步任务队列如何保证在服务器宕机时不丢失任何一条 AI 回复?
运维·服务器·人工智能·python·websocket·fastapi·实时通信
kc胡聪聪9 小时前
nginx的性能优化与监控
运维·nginx·性能优化
楼兰胡杨10 小时前
面试题|MySQL 的 3 层主键索引最多能支撑多少数据量
mysql·面试题
上海合宙LuatOS10 小时前
LuatOS核心库API——【sys】LuatOS运行框架
运维·服务器·物联网·硬件工程·lua·软件工程·信息与通信
运维行者_10 小时前
网络监控方案从零开始 -- 企业级完整指南
大数据·运维·服务器·网络·数据库·人工智能·自动化