首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >pt-archiver报错一则: 时间字段类型错误问题

pt-archiver报错一则: 时间字段类型错误问题

原创
作者头像
保持热爱奔赴山海
发布2026-04-15 10:40:31
发布2026-04-15 10:40:31
260
举报
文章被收录于专栏:数据库相关数据库相关

报错场景

最近一个跑了挺久的数据清理任务报错了,报错日志提示 Truncated incorrect datetime value: '2026-04-14 00:03:341455'

dba人工执行pt-archiver脚本,可以复现,如下图:

看了下表结构,大致如下:

代码语言:txt
复制
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参数,类似:

代码语言:txt
复制
/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时间字段的可行性

为什么之前没有遇到这个问题

1. 触发了“脏数据”地雷(最可能的原因)

报错的值 '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 变严格了,也会导致旧数据在读取时暴露问题。

可以看下面的例子

代码语言:txt
复制
[本机测试]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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 报错场景
  • 修改方法
  • 为什么之前没有遇到这个问题
    • 1. 触发了“脏数据”地雷(最可能的原因)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档