首页 > 数据库 >字符集collation不同-隐式转换mysql

字符集collation不同-隐式转换mysql

时间:2023-11-10 17:31:54浏览次数:42  
标签:cust utf8mb4 no yhtest COLLATE mysql collation NULL 隐式

适用范围

1.适用于MySQL 或者Oceanbase for MySQL
2.适用于两表或多表join 的字段字符序不同的场景。
如本例:

COLLATE utf8mb4_general_ci 和 COLLATE utf8mb4_bin
 `cust_no` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci 
 `cust_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin

问题概述

两表或者多表Join 因Join字段的字符序不同,导致产生隐式转换而无法使用到index。详细的原理内容请参考文章末尾的参考文档。以供大家参考。(早前有写过Oceanbase For MySQL隐式转换的类似案例。)

问题原因

对两表或多表Join的连接字段各自指定了字符序,但指定的不一致,导致产生隐式转换。(本例就属于这类。)
也有在我服务的客户这边,因MySQL 或Oceanbase For MySQL的开发规范规定表的字符序需要为utf8mb4_bin,偏偏这两类数据库如果表的字符集选择utf8mb4字符序不指定,则默认的字符序为:utf8mb4_general_ci,由于有的开发人员会落实开发规范的差异,导致两表或多表Join的字段因字符序的不同而产生隐式转换成为一项比较普遍存在的问题。

详细过程

原始SQL

SELECT count(1) locationCount
			FROM yhtest_base_addrs_info a
			LEFT JOIN wyh_testinfo_location b 
			ON a.cust_no = b.cust_no
			WHERE b.location IS NULL
			AND a.address IS NOT NULL

原始SQL 的执行时间及执行计划

-- 原始SQL 执行时间

用户反馈长时间执行不出结果。

-- 原始SQL 执行计划

+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra                                          |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
|  1 | SIMPLE      | a     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1880706 |    90.00 | Using where                                    |
|  1 | SIMPLE      | b     | NULL       | ALL  | PRIMARY       | NULL | NULL    | NULL | 1828366 |    10.00 | Range checked for each record (index map: 0x1) |
+----+-------------+-------+------------+------+---------------+------+---------+------+---------+----------+------------------------------------------------+
2 rows in set, 2 warnings (0.01 sec)

-- 原始SQL 执行计划warning信息。

root@localhost [yhtest]> show warnings;
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                       |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1739 | Cannot use ref access on index 'PRIMARY' due to type or collation conversion on field 'cust_no'                                                                                                                                                                               |
| Note    | 1003 | /* select#1 */ select count(1) AS `locationCount` from `yhtest`.`yhtest_base_addrs_info` `a` left join `yhtest`.`wyh_testinfo_location` `b` on((`yhtest`.`a`.`cust_no` = `yhtest`.`b`.`cust_no`)) where ((`yhtest`.`b`.`location` is null) and (`yhtest`.`a`.`address` is not null)) |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

从执行计划看a,b 两表Join没什么index可使用到。但执行计划有warnings,(通常有隐式转换的执行计划下面均有warnings,需要show warnings可以看到详细的隐式转换字段。)
通过show warnings可见 cust_no 字段有隐式转换。Cannot use ref access on index ‘PRIMARY’ due to type or collation conversion on field ‘cust_no’

另外关于 Range checked for each record (index map: 0x1) 的描述参考官网: EXPLAIN Output Format

相关表基础信息

-- 表信息
CREATE TABLE `yhtest_base_addrs_info` (
  `cust_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '客户编号',
  `address` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '地址信息',

  PRIMARY KEY (`cust_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;


CREATE TABLE `wyh_testinfo_location` (
  `cust_no` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户编号',
  `location` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '经纬度(根据地址通过百度地图api获得)',
  PRIMARY KEY (`cust_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ;
-- 表数据量

root@localhost [yhtest]> select count(*) from yhtest_base_addrs_info where address IS NOT NULL;
+----------+
| count(*) |
+----------+
|  1774412 |
+----------+
1 row in set (0.69 sec)

root@localhost [yhtest]> select count(*) from wyh_testinfo_location where location IS NULL;
+----------+
| count(*) |
+----------+
|  1151313 |
+----------+
1 row in set (0.44 sec)

发现表cust_no为两表的主键。
但 两表collation不同

`cust_no` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci 
 `cust_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin

修改字符序消除隐式转换

alter table wyh_testinfo_location modify cust_no varchar(30) character set utf8mb4 collate utf8mb4_bin;

消除隐式转换后的执行时间及执行计划

-- 执行时间
+---------------+
| locationCount |
+---------------+
|       1202357 |
+---------------+
1 row in set (5.78 sec)

-- 执行计划
``` language
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref             | rows    | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+---------+----------+-------------+
|  1 | SIMPLE      | a     | NULL       | ALL    | NULL          | NULL    | NULL    | NULL            | 1880706 |    90.00 | Using where |
|  1 | SIMPLE      | b     | NULL       | eq_ref | PRIMARY       | PRIMARY | 122     | yhtest.a.cust_no |       1 |    10.00 | Using where |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+---------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

结论:

该案例两表Join 的连接字段因字符序不同引起的隐式转换,通过修改统一连接字段的字符序而使长时间执行不出结果的SQL 的执行时间提升到了5.78 sec出结果。

标签:cust,utf8mb4,no,yhtest,COLLATE,mysql,collation,NULL,隐式
From: https://blog.51cto.com/u_13482808/8305502

相关文章

  • 解决MySQL8报错:Public Key Retrieval is not allowed
    问题分析:这个是由于配置的URL中的useSSL为false导致的,当其为false后,mysql将会检查allowPublicKeyRetrieval是不是TRUE,由于开启allowPublicKeyRetrieval不安全可能遭到中间人攻击(英语:Man-in-the-middleattack,缩写:MITM),所以allowPublicKeyRetrieval的值默认为false。两项都为false后......
  • MySQL数据库进阶实战:优化性能、提高安全性和实现高可用性
    当涉及到MySQL数据库的进阶实战时,有许多方面需要考虑,包括性能优化、安全性、高可用性和复杂查询等。以下是一个关于MySQL数据库进阶实战的文章大纲,您可以根据需要进行扩展和详细说明。MySQL数据库进阶实战:优化性能、提高安全性和实现高可用性引言MySQL是一款广泛使用的开源关系型数......
  • 以下哪些语句触发了隐式的类型转换?
    AparseInt(12.34,10)B0?1:2C2e1*0xaaD1+'1'正确答案:ABDparseInt()函数可解析一个字符串,并返回一个整数。所以说,number类型的12.34发生隐式转换为string。三元运算符,会判断?前的表达式为true或者false。所以number类型的0发生了隐式转换为boolean。+运算发生......
  • 为MySQL新增一张performance_schema表 | StoneDB 技术分享会 #4
    StoneDB开源地址https://github.com/stoneatom/stonedb设计:小艾审核:丁奇、李浩编辑:宇亭作者:王若添中国科学技术大学-软件工程-在读硕士、StoneDB内核研发实习生performance_schema简介MySQL启动后会自动创建四个databasemysql>showdatabases;+--------------------+|Da......
  • MySQL导入导出数据表容量的一个问题场景
    朋友提了一个MySQL数据导出导入的问题。问题描述:从源库(兼容MySQL协议的TDSQL,selectversion()=5.7,test表字符集是utf8,test是个分区表)通过如下指令,导出一份数据,SQL格式的,文件6G,mysqldump-hx.x.x.x-P3306-uroot-proot--databasesdbtest--tablestest--complete-insert--s......
  • mysql 查询报错Expression #1 of SELECT list is not in GROUP BY clause and contain
    这个错误是由于MySQL的新版本中默认开启了ONLY_FULL_GROUP_BY模式,即在GROUPBY语句中的SELECT列表中,只能包含分组或聚合函数,不能包含其他列。而你的查询语句中出现了一个列senior_two.score.student_id,它既没有被分组也没有被聚合,因此MySQL报出了这个错误。5.7版本以下不......
  • docker mysql
    dockerrun-d--namemysql--restart=always--privileged=true\-v/opt/mysql/log:/var/log/mysql\-v/opt/mysql/data:/var/lib/mysql\-v/opt/mysql/conf.d:/etc/mysql/conf.d\-v/etc/localtime:/etc/localtime:ro\-eMYSQL_ROOT_PASSWORD=123456-p33......
  • MySQL 死锁后事务无法回滚是真的吗?
    MySQL作为目前互联网企业使用最多的,或者说在基于成本下,最流行的数据库之一,MySQL在国内使用者众多,那么在MySQL偶然安装后,在使用中出现死锁后,死锁中的事务到底能不能回滚 ?我们来进行相关的实验我们先验证一遍1 我们打开一个MySQL版本为8.027 官方版本2通过下面的操作我们可以......
  • MySQL 内部Server 层机制
    主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。1.连接器像navicat、JDBC、MySQL等客户端软件需要先和mysql建立通信之后......
  • MySQL8
    MySQL8.0:窗口函数一、MySQL8.0窗口函数概述1、什么是窗口函数窗口函数是类似于可以返回聚合函数值的函数,例如SUM(),COUNT(),MAX()。但是窗口函数又与普通的聚合函数不一样,它不会对结果进行分组,使输出中的行数和输入中的行数相同。窗口函数示例:selectsum()over(partitionby_......