
最近一个跑了挺久的数据清理任务报错了,报错日志提示 Truncated incorrect datetime value: '2026-04-14 00:03:341455'
dba人工执行pt-archiver脚本,可以复现,如下图:

看了下表结构,大致如下:
CREATE TABLE `sbt1` (
`id` varchar(50) NOT NULL COMMENT 'id',
`request_id` varchar(100) DEFAULT NULL COMMENT '请求id',
`file_path` varchar(200) DEFAULT NULL COMMENT '文件路径',
`create_time` varchar(50) DEFAULT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
)可以看到这个create_time字段是字符串类型,而不是我们预期的datetime时间类型。
1、在pt-archiver过程中,加上 设置会话级别的sql_mode参数,类似:
/usr/bin/pt-archiver \
--source h=192.168.31.181,u=dba,p=123456,P=3306,D=sbtest,t=sbt1 \
--no-check-charset --limit 1000 --txn-size 1000 \
--statistics --skip-foreign-key-checks \
--set-vars="sql_mode=''" \
--purge --bulk-delete --progress 2000 \
--no-version-check \
--where "create_time<DATE_ADD(now(), interval -1 month)"2、pt-archiver时候换一个datetime类型的字段,例如 update_time 字段,具体还需要根据业务场景去决定。
如果其他字段能解决的话,推荐这种方案,不需要开发协助做改动。
3、联系业务方,评估将create_time改为datetime时间字段的可行性
报错的值 '2026-04-14 00:03:341455' 是一个非法的 DATETIME 格式。标准的 DATETIME 格式是 YYYY-MM-DD HH:MM:SS(19位),报错的值后面多了 1455(看起来像是微秒被错误地拼接到秒后面了,变成了23位)。
为什么之前没报错?
数据是后来写入的:这条“脏数据”可能是在最近一次业务写入时产生的。之前的清理任务运行时,这条数据还不存在,所以没有触发错误。
写入时的宽容:在写入这条数据时,数据库的 sql_mode 可能比较宽松(例如没有开启 STRICT_TRANS_TABLES),导致程序传入一个带微秒的时间字符串时,MySQL 没有报错,而是将其“截断”或“畸形”地存了进去。
读取时的严格:pt-archiver 在读取或比较数据时,MySQL 会尝试将这个畸形的字符串转换回 DATETIME 对象进行比较,这时就会因为格式严重不符而抛出 Truncated incorrect datetime value 错误。
结论:表结构没变,但表里多了一条不符合结构定义的“坏数据”,之前的清理任务没扫到它,这次扫到了。
2. pt-archiver 的内部机制差异
pt-archiver 的工作方式不是一条条简单的 DELETE,它会先 SELECT 出要删除的数据,或者在 DELETE 的 WHERE 条件中引用主键范围。
隐式转换:报错的 SQL 是 DELETE ... WHERE ... create_time < ...。MySQL 在执行这个比较时,必须确保 create_time 列的值是合法的日期时间。
批次差异:pt-archiver 是分批次处理的。可能前几个批次处理的数据都是干净的,直到处理到包含这条脏数据(ID 在 'f514c03f...' 到 'f5e9f13e...' 之间)的批次时,才触发了类型转换错误。
3. 数据库会话配置(sql_mode)的变化
即使表结构不变,数据库的运行参数变了也会导致行为不同。
连接配置:如果这次执行 pt-archiver 的客户端(或连接池)配置的 sql_mode 比之前更严格(例如开启了 STRICT_ALL_TABLES 或 NO_ZERO_DATE),那么以前能“混过去”的非法数据,现在就会被拦截。
MySQL 版本/配置更新:如果数据库服务器最近做过重启或配置变更,导致全局的 sql_mode 变严格了,也会导致旧数据在读取时暴露问题。
可以看下面的例子
[本机测试]root@localhost [test] > show create table ttt \G
*************************** 1. row ***************************
Table: ttt
Create Table: CREATE TABLE `ttt` (
`a` int DEFAULT NULL,
`b` varchar(50) DEFAULT NULL,
`c` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
[本机测试]root@localhost [test] > insert into ttt select 1,'2026-04-14 01:03:341455','2026-04-14 01:03:341455';
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 1
[本机测试]root@localhost [test] > insert into ttt select 2,'2026-04-14 01:03:34','2026-04-14 01:03:34';
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0 --> 注意看,只有这条记录插入的时候没有warning
[本机测试]root@localhost [test] > insert into ttt select 3,'2026-04-14 01:03:341','2026-04-14 01:03:341';
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 1
[本机测试]root@localhost [test] > insert into ttt select 4,'2026-04-14 01:03:3414','2026-04-14 01:03:3414';
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 1
[本机测试]root@localhost [test] > insert into ttt select 5,'2026-04-14 01:03:34145','2026-04-14 01:03:34145';
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 1
[本机测试]root@localhost [test] > select * from ttt;
+------+-------------------------+---------------------+
| a | b | c |
+------+-------------------------+---------------------+
| 1 | 2026-04-14 01:03:341455 | 0000-00-00 00:00:00 |
| 2 | 2026-04-14 01:03:34 | 2026-04-14 01:03:34 |
| 3 | 2026-04-14 01:03:341 | 0000-00-00 00:00:00 |
| 4 | 2026-04-14 01:03:3414 | 0000-00-00 00:00:00 |
| 5 | 2026-04-14 01:03:34145 | 0000-00-00 00:00:00 |
+------+-------------------------+---------------------+
如果我们想看到具体的warning的话,可以再插入一条试试看
[本机测试]root@localhost [test] > insert into ttt select 6,'2026-04-14 01:03:34145','2026-04-14 01:03:34145';
Query OK, 1 row affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 1
[本机测试]root@localhost [test] > show warnings;
+---------+------+----------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 'c' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)
很明显,这类数据
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。