varchar超长问题

【 TiDB 使用环境】测试
【 TiDB 版本】5.4
背景:新建表和原表 表结构及字符集 相同,原表业务数据 要导入新表,报错:ERROR 1406 (22001): Data Too Long, field len 225, data len 336
排查是字段类型为varchar(225)的字段导致,想问,原表数据是如何插入进去的?

v5.4版本,VARCHAR 的空间占用大小不得超过 65535 字节。在选择 VARCHAR 长度时,应当根据最长的行的大小和使用的字符集确定。

utf8mb4下VARCHAR 最大列长度的取值范围是(0, 16383] 。

https://docs.pingcap.com/zh/tidb/v5.4/data-type-string

1 个赞

确认下新建表 和与原表的表结构,确认这两个字段的定义情况是否一致

完全一样,粘贴复制的,原表是业务跑进来的数据,我要把数据导入到新表,导不进去

查看一下是不是真的有长度336的数据。

出现这个问题,一般都是实际数据长度不符合表结构的定义长度所导致的。
鉴于楼主你这个是测试环境,看看能否在原表再插入相同的字段数据,先尝试复现问题。
也可以把表和数据脱敏后提供上来,大家一起看看。

确实有

单独拿出那条数据,插入不了,现在就是不清楚,原表是怎么插入进去的,是有什么设置嘛,比如sql_mode

那只能增加目标数据库的字符长度了。
确实有类似的案例,也不是字符集引起的。

什么原因查不到嘛

貌似都是老版本,我看到的案例是4.0的。
应该跟SQL_MODE无关,即使是非严格模式,理论上也是截断,而非把超长数据存进去。

1 个赞

sql_mode 一般是检查数据是否符合要求,如果设置了在不符合时会报错,不设置就会打印warning而不报错,但是数据会被截断插入。如:

mysql> select version();
+--------------------+
| version()          |
+--------------------+
| 5.7.25-TiDB-v5.4.0 |
+--------------------+
1 row in set (0.00 sec)
mysql> show variables like '%sql_mode%';
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> create table a (name varchar(3));
Query OK, 0 rows affected (0.07 sec)
mysql> insert into a (name) values ('1234');
ERROR 1406 (22001): Data too long for column 'name' at row 1
mysql>
mysql> insert into a (name) values ('123');
Query OK, 1 row affected (0.01 sec)

mysql> set sql_mode="";
Query OK, 0 rows affected (0.00 sec)
mysql> insert into a (name) values ('1234');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> show warnings;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1406 | Data Too Long, field len 3, data len 4 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

mysql> select * from a ;
+------+
| name |
+------+
| 123  |
| 123  |
+------+
2 rows in set (0.00 sec)

和sql_mode没关系。

而且常规的通过tidb-server的访问,我这边验证是正常的,没能复现楼主说的现象。

我们是4.0版本升到5.4的

当初是原地升级?

可以贴一下新旧表结构么?感觉book思议~
另外手工查一下,老数据真的是336么?

1 个赞

是不是有乱码导致的,之前遇到过两边结构相同,但是过程中有乱码,目标端按照乱码计算的,超长了

贴一下源端和目标段的表结构,sql_mode,还有两边的db 版本

这种问题需要确认原表插入数据后是否有 tidb 版本升级,sql_mode模式是否有变化?

对新旧表 show create table 一把呗。感觉不应该不一致

看看是不是存的汉字,是不是二个表占的位数不一样