MySQL按Unix时间戳创建每日分区报错1486的解决方案求助
错误原因分析
错误1486的核心问题是分区函数中使用了非确定性/依赖时区的表达式:TO_DAYS(UNIX_TIMESTAMP(updated_at)) 这个嵌套函数组合会引入时区依赖(UNIX_TIMESTAMP转换时受服务器时区影响),同时不符合MySQL分区函数的确定性要求。
另外还有一个隐藏问题:InnoDB引擎下,分区列必须包含在主键或唯一键中(当前主键仅为id,分区列是updated_at,解决第一个错误后会触发此问题)。
解决步骤
1. 简化分区函数,直接使用时间戳字段
updated_at是int类型的时间戳,无需额外转换,直接用它作为RANGE分区的依据。同时将分区边界转换成对应时间戳值:
- 执行
SELECT UNIX_TIMESTAMP('2023-04-10');可获取2023-04-10 00:00:00对应的时间戳(示例值为1681065600),直接用该数值作为分区边界。
2. 调整主键,包含分区列
InnoDB要求分区列必须是主键的一部分,因此需修改主键为(id, updated_at)(id本身自增唯一,添加updated_at后仍保证主键唯一性)。
修正后的SQL语句
CREATE TABLE IF NOT EXISTS `ds_shipment_container_new` ( `id` int(11) NOT NULL AUTO_INCREMENT, `company_id` int(11) NOT NULL, `company_code` varchar(50) NOT NULL, `warehouse_id` int(11) NOT NULL, `warehouse_code` varchar(50) NOT NULL, `shipment_header_id` int(11) NOT NULL, `shipment_number` varchar(100) DEFAULT NULL, `shipment_container_id` int(11) NOT NULL, `ship_to_name` varchar(100) DEFAULT NULL, `ship_to_country` varchar(100) NOT NULL, `carrier` varchar(70) NOT NULL, `carrier_service` varchar(70) NOT NULL, `carrier_zone_code` varchar(30) DEFAULT NULL, `container_number` varchar(255) DEFAULT NULL, `container_type` varchar(80) DEFAULT NULL, `total_quantity` int(11) DEFAULT 0, `total_weight` double DEFAULT 0, `total_volume` double DEFAULT 0, `created_at` int(11) DEFAULT UNIX_TIMESTAMP(), `updated_at` int(11) DEFAULT UNIX_TIMESTAMP(), PRIMARY KEY (`id`, `updated_at`) USING BTREE, -- 调整主键,包含分区列 KEY `updated_at` (`updated_at`) USING BTREE, UNIQUE KEY `shipment_container_id` (`shipment_container_id`) USING BTREE ) PARTITION BY RANGE (`updated_at`) ( PARTITION p1 VALUES LESS THAN (1681065600), -- 对应2023-04-10 00:00:00的时间戳 PARTITION p2 VALUES LESS THAN (MAXVALUE) );
额外可选方案
如果偏好使用日期格式的分区边界,建议将updated_at字段类型改为datetime或timestamp,此时可直接用TO_DAYS(updated_at)作为分区函数,同时仍需将updated_at加入主键:
CREATE TABLE IF NOT EXISTS `ds_shipment_container_new` ( -- 其他字段保持不变 `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`, `updated_at`) USING BTREE, KEY `updated_at` (`updated_at`) USING BTREE, UNIQUE KEY `shipment_container_id` (`shipment_container_id`) USING BTREE ) PARTITION BY RANGE (TO_DAYS(`updated_at`)) ( PARTITION p1 VALUES LESS THAN (TO_DAYS('2023-04-10')), PARTITION p2 VALUES LESS THAN (MAXVALUE) );
内容的提问来源于stack exchange,提问作者Adan Op
相关产品推荐
相关产品推荐

