字符集排序规则造成like模糊查询返回错误数据

【 TiDB 使用环境】生产环境 or 测试环境 or POC
测试、生产环境
【 TiDB 版本】
v5.0.6
【遇到的问题】
在tidb中,语句select * from t_like where name like '房%'查询无返回数据,而再mysql里面可以正常返回数据
【复现路径】做过哪些操作出现的问题
【问题现象及影响】
TiDB中:
1、查看是否启用新排序规则
SELECT VARIABLE_VALUE FROM mysql.tidb WHERE VARIABLE_NAME=‘new_collation_enabled’;
±---------------+
| VARIABLE_VALUE |
±---------------+
| True |
±---------------+
1 row in set (0.01 sec)
2、查看字符集
show global variables like ‘%coll%’;
±-----------------------------------±-------------------+
| Variable_name | Value |
±-----------------------------------±-------------------+
| collation_connection | utf8mb4_general_ci |
| collation_database | utf8mb4_general_ci |
| collation_server | utf8mb4_general_ci |
| tidb_enable_collect_execution_info | ON |
±-----------------------------------±-------------------+
3、建表重现问题
表排序规则是utf8mb4_general_ci,不是tidb默认的utf8mb4_bin
CREATE TABLE t_like (
id int(11) NOT NULL,
name varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
KEY idx_name (name),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
insert into t_like values(1,‘房房房’),(2,‘子子子’);
select * from t_like;
±—±----------+
| id | name |
±—±----------+
| 1 | 房房房 |
| 2 | 子子子 |
±—±----------+
2 rows in set (0.01 sec)
select * from t_like where name like ‘房房%’;
Empty set (0.00 sec)
select * from t_like where name like ‘房房房%’;
Empty set (0.00 sec)
select * from t_like where name like ‘子子%’;
±—±----------+
| id | name |
±—±----------+
| 2 | 子子子 |
±—±----------+
1 row in set (0.01 sec)
select * from t_like where name like ‘子子子%’;
±—±----------+
| id | name |
±—±----------+
| 2 | 子子子 |
±—±----------+
1 row in set (0.01 sec)

如上所示查询汉字‘房’时无数据返回,应该要返回数据,汉字‘子’就正常返回

在MySQL中:
1、查看字符集
show global variables like ‘%coll%’;
±---------------------±-------------------+
| Variable_name | Value |
±---------------------±-------------------+
| collation_connection | utf8mb4_general_ci |
| collation_database | utf8mb4_general_ci |
| collation_server | utf8mb4_general_ci |
±---------------------±-------------------+
3 rows in set (0.00 sec)
2、建表重现问题
CREATE TABLE t_like (
id int(11) NOT NULL,
name varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
KEY idx_name (name),
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
insert into t_like values(1,‘房房房’),(2,‘子子子’);
select * from t_like where name like ‘房房%’;
±—±----------+
| id | name |
±—±----------+
| 1 | 房房房 |
±—±----------+
1 row in set (0.00 sec)
select * from t_like where name like ‘房房房%’;
±—±----------+
| id | name |
±—±----------+
| 1 | 房房房 |
±—±----------+
1 row in set (0.00 sec)

如上所示查询汉字‘房’时正常数据返回

在模糊查询的汉字是‘房’时候会出现这个问题,应该还要其他汉字也会出现,但是没有验证出来,难道这个字有啥特殊的地方?这个不确定性比较麻烦

之后又在tidb中将t_like表的排序规则改为tidb默认的utf8mb4_bin,则查询时正常返回数据,但生产环境为了跟MySQL兼容,在参数、库和表级别排序规则都是utf8mb4_general_ci,无法修改。

【附件】

utf8mb4_bin是区分大小写的,也区分e和é这类字符的
utf8_genera_ci是不区分大小写的,也不区分e和é这类字符

utf8mb4_general_ci 也适用德语、法语或者俄语,但会有不准。如果你的应用能够接受这些,那么应该使用 utf8mb4_general_ci,因为它速度快。否则,使用utf8mb4_unicode_ci,因为它比较准确。

1 个赞

排序规则跟是否能查出数据没什么关系吧,我觉得有点像bug,不过我在6.0测试环境没能复现。

感觉和排序没啥关系

我也觉得是个bug,是在非默认排序规则下的bug,5.0之后字符集utf8mb4的默认排序规则是utf8mb4_bin,而现在为了跟原来的MySQL兼容在启用tidb新排序规则框架后使用了utf8mb4_general_ci,这个非默认排序规则和新排序框架情况应该测试覆盖不充分,like模糊查询某些数据跟MySQL返回结果不一致。

另外排序规则改为utf8mb4_unicode_ci,在TiDB中还是无法返回数据,在MySQL中是可以正常返回的

先要查出来,我们再来谈排序。
我虽然没有复现,但是觉得可能和编码有关。你前后%,看看能出吗?

前后都模糊查询,可以正常返回

部署tidb时候,有如下3个地方配置调整,其他都是默认的
– 1
server_configs:
tidb:
new_collations_enabled_on_first_bootstrap: true

– 2
set global collation_connection = utf8mb4_general_ci;
set global collation_database = utf8mb4_general_ci;
set global collation_server = utf8mb4_general_ci;

– 3
set global tidb_enable_clustered_index = off; --修改默认值为非聚簇索引

又测试了一下,看上去还是与排序规则有关系

发一下前后的执行计划。

表结构
t_like排序规则是utf8mb4_general_ci,作为对照t_like2的排序规则是utf8mb4_bin

表数据

执行计划

麻烦再确认一下,plan cache 开了吗?

是已知 bug,新版本已经修复。建议更新到最新版本。

多谢了,我也验证了v6.0.0版本,没有这个问题了。

难怪啊,是bug就解释得通了。否则不应该。5有这个问题吗?因为我们一般不允许前后%

v5.0.2、v5.0.6、v5.4.0都验证过,有的。

另外,右模糊有些场景我们还是有用的

非常感谢。这是较大的坑啊。那我们早点用6吧

此话题已在最后回复的 1 分钟后被自动关闭。不再允许新回复。