SQL隐式转换导致索引失效_字符集不一致

梦莱2年前技术文章1285

3.字符集不一致导致索引失效

示例 SQL 如下,通过查看执行计划发现 XXX 和 XXXX 表在进行表关联的时候没有走索引,导致 SQL 扫描数量较大。核实表结构发现表关联对应列都存在索引,最终查看字符集发现,两个表的字符集不同存在隐式转换。

--当前SQL
--DB:lefit_live
SELECT ........
FROM XX lu
LEFT JOIN (
SELECT r.*
FROM XXXXX r
WHERE r.is_delete != 1
GROUP BY r.phone
) luw
ON lu.phone = luw.phone
LEFT JOIN XXX luc ON luc.user_id = lu.user_id
LEFT JOIN XXXX lcc ON lcc.channel_code = luc.channel_code
WHERE 1 = 1
AND lu.user_id = 11111
LIMIT 0, 2

查看表结构发现 lcc 表字符集为 utf8,但是 luc 表字符集为 utf8mb4。utf8mb4和utf8两种不同字符集(编码)类型的字符串在做⽐较时,MySQL会先把utf8 字符串转成utf8mb4 字符集,再做⽐较,这就导致了隐式转换的出现。

utf8mb4 是 utf8 的超集,在做隐式⾃动类型转换时,为了避免数据在转换过程中由于截断导致数据错误,会按数据长度增加的⽅向进⾏转换。

该情况可以通过两种方法进行优化。1.修改表字符集。ALTER table 表名 CHARACTER SET 字符集名称;但该方法一般不推荐,首先需要保证该表可以改为 utf8 字符集;其次还要保证修改后,其他使用该表进行表连接的 SQL 不会出现隐式转换问题;且本身 DDL 就是一个比较消耗资源的操作。2.通过修改 SQL 完成优化。可以通过给驱动表关联列加 convert() 函数,使其临时修改成一致的字符集,进行优化。具体改写 SQL 如下:

--改写后
SELECT lu.user_id, lu.phone, lu.nick_name, lu.head_img, lu.gender
, lu.birthday, lu.status, lu.ctime AS reg_time, luc.ctype, luc.channel_code
, lcc.name AS channel_name, luc.source_id, luw.nickname AS wx_nick_name, luw.unionid
FROM XX lu
LEFT JOIN (
SELECT r.*
FROM XXXXX r
WHERE r.is_delete != 1
GROUP BY r.phone
) luw
ON lu.phone = luw.phone
LEFT JOIN XXX luc ON luc.user_id = lu.user_id
LEFT JOIN XXXX lcc ON lcc.channel_code =convert(luc.channel_code USING utf8)
WHERE 1 = 1
AND lu.user_id = 11111
LIMIT 0, 2

--如需修改数据库字符集可以按照如下语句调整
ALTER TABLE biz_circulateitem DEFAULT CHARACTER SET utf8 ;

改写后,表关联列可以正常走上索引,扫描量大大减少。

表连接过程中,被驱动表的索引字段上加函数操作,会导致对被驱动表做全表扫描。因此在进行函数添加时,应选择将驱动表的字符集修改为被驱动表的字符集。


相关文章

Apache Ranger不使用root密码进行初始化

1、背景由于使用的数据库由dba进行管理,我们无法获取到对应的ranger数据库的root密码。需要使用数据库普通用户对表进行初始化2、解决ranger admin每次修改配置(install.pro...

k8s service IP不能ping通?

k8s service IP不能ping通?

1、先看下serviceIP是怎么来的?serviceIP是serviceController生成的,参数--service-cluster-ip-range string会配置在controller...

数据湖技术之iceberg(十二)Flink与Iceberg整合-SQL API操作

数据湖技术之iceberg(十二)Flink与Iceberg整合-SQL API操作

1.SQL API 创建Iceberg表并写入数据StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnv...

MySQL运维实战(5.1) 字符和编码的基本概念

MySQL运维实战(5.1) 字符和编码的基本概念

字符和编码字符字符是符号,是人们用于交流的各类符号,如26个英文字母、汉字、标点符号、数学运算符、其他语言的字母和符号。编码编码是计算机中以二进制方式存储字符的方式。字符集字符集是字符和编码的映射表。...

trino容器对接hudi(五)

trino容器对接hudi(五)

前提:本文是基于已经部署了trino容器的基础上进行的。冒烟测试是在trino对接ldap后并且ranger已经对接了metastore权限后,并且spark组件已经对接hudi,并且成功创建hudi...

Hbase Rowkey设计方法

良好的 rowkey 设计,应当遵循以上四大原则,并且能让数据分散,从而避免热点问题。下面是几种常用的 rowkey 设计方法。1 Salt 加盐这里说的 Salt 加盐方法,是给每一个 rowkey...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。