0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MySQL字符集不一致导致索引失效的案例分析

jf_78858299 来源:阿Q说代码 作者:不剪发的Tony老师 2023-03-02 09:59 次阅读

问题描述

有个朋友给我发来一个问题,说是他们的系统有几十万用户,某个查询需要 5 秒以上的时间才能返回,同时服务器 CPU 资源占用率将近 100%。这个对于用户的线上操作影响非常大,那么我们就来看看如何分析和解决这个慢查询问题。

为了便于说明问题,我们对表结构进行了简化:

create table customer(
  cid int auto_increment primary key,
  cname varchar(50) not null,
  register_time datetime not null,
  recommender varchar(50) character set utf8
) engine=innodb default charset=utf8mb4;

create unique index uk_customer_cname on customer(cname);

insert into customer(cname, register_time, recommender) values('张三', now(), '');
insert into customer(cname, register_time, recommender) values('李四', now(), '张三'),('王五', now(), '李四');
  • • customer 是用户表,其中 cid 是主键;
  • • cname 上有一个唯一索引
  • • recommender 是用户的推荐人。

实际查询涉及了很多表,经过简化之后存在性能问题的语句如下:

select c.*
from customer c
join customer r on (c.recommender = r.cname )
where r.cid = 1
and c.register_time between now() - interval 1 day and now();

大意是查找通过某人推荐,在指定时间段内注册的用户。

问题分析

了解问题之后,首先我让他给我发来了 explain 执行计划:

explain
select c.*
from customer c
join customer r on (c.recommender = r.cname )
where r.cname = '张三'
and c.register_time between now() - interval 1 day and now();

id|select_type|table|partitions|type |possible_keys    |key              |key_len|ref  |rows|filtered|Extra      |
--|-----------|-----|----------|-----|-----------------|-----------------|-------|-----|----|--------|-----------|
 1|SIMPLE     |r    |          |const|uk_customer_cname|uk_customer_cname|202    |const|   1|   100.0|Using index|
 1|SIMPLE     |c    |          |ALL  |                 |                 |       |     |   3|   33.33|Using where|

从结果可以看出,有一个全表扫描(type = ALL)的操作,显然这是因为 recommender 字段上缺少索引。

所以,我们首先为 recommender 字段创建了一个索引:

create index idx_customer_cname on customer(recommender);

之后再次查看了执行计划,结果没有任何变化,创建的索引没有生效。然后我们使用了 show warnings 命令看看有没有更多的信息

show warnings\\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select `hrdb`.`c`.`cid` AS `cid`,`hrdb`.`c`.`cname` AS `cname`,`hrdb`.`c`.`register_time` AS `register_time`,`hrdb`.`c`.`recommender` AS `recommender` from `hrdb`.`customer` `c` join `hrdb`.`customer` `r` where ((`hrdb`.`c`.`register_time` between

这里有一个问题,就是存在字符集转换:

convert(`hrdb`.`c`.`recommender` using utf8mb4) = '张三')

recommender 需要转换为 utf8mb4 字符集,查看表结构之后发现它的字符集是 utf8,和表中的其他字段字符集不一样。原来他们是从之前的版本迁移过来的表结构,不知怎么会导致遗留一个字段的字符集忘记了调整。

MySQL 支持数据库、表以及字段级别的字符集(Character Set)和排序规则(Collation)。不同字符集支持的字符种类和数量不同,例如 ASCII 字符集只能存储字母、数字和常见的符号,GB2312 和 GB18030 可以支持中文,Unicode 字符集能够支持多国语言;排序规则定义了字符的排序顺序,例如是否区分大小写、是否区分重音、中文按照拼音还是偏旁进行排序等。

接下来就是修改字段的字符集了:

alter table customer modify column recommender varchar(50) character set utf8mb4;

然后,再次查看执行计划的结果如下:

id|select_type|table|partitions|type |possible_keys     |key               |key_len|ref  |rows|filtered|Extra      |
--|-----------|-----|----------|-----|------------------|------------------|-------|-----|----|--------|-----------|
 1|SIMPLE     |r    |          |const|uk_customer_cname |uk_customer_cname |202    |const|   1|   100.0|Using index|
 1|SIMPLE     |c    |          |ref  |idx_customer_cname|idx_customer_cname|203    |const|   1|   33.33|Using where|

在实际环境中优化之后的查询需要 0.1 秒左右,已经完全可以满足业务的需求了。

总结

本文分析了一个由于字符集不一致,导致增加了索引但是无法使用的案例。通过索引进行查找时需要进行数据的比较,字符集不一致时需要使用 convert 函数进行转换,从而导致索引失效。通常在迁移遗留系统时需要特别小心,对于 Unicode 推荐使用最新的 utf8mb4 字符集。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10863

    浏览量

    211735
  • 服务器
    +关注

    关注

    12

    文章

    9157

    浏览量

    85411
  • MySQL
    +关注

    关注

    1

    文章

    809

    浏览量

    26559
收藏 人收藏

    评论

    相关推荐

    AD9910初始相位不一致

    调试AD9910的DRG模式的时候,目前能出线性调频信号,但是会出现相位不一致,初始相位直在跳,因为DRG模式可以选择频率、相位、幅度三个中个进行控制,我目前是控制的频率,请问怎么能解决这个相位
    发表于 10-24 15:49

    字符集字符集编码详解

    字符集字符集编码详解
    发表于 09-12 08:33 4次下载
    <b class='flag-5'>字符集</b>与<b class='flag-5'>字符集</b>编码详解

    基于偏好不一致熵的偏好决策方法

    针对多规则有序决策系统中的偏好决策问题,根据有序决策的偏好不一致特性,提出了种基于偏好不一致熵的偏好决策方法。首先,定义了样本的偏好不一致熵( PIEO),用来度量特定样本相对于样本
    发表于 12-05 11:50 0次下载

    感兴趣区域不一致性决策算法

    医学影像感兴趣区域( ROI)的噪声和疾病误判是个典型的不一致性决策问题,同时也是困扰临床诊断的个难题。针对这个问题,基于宏观与微观结合、全局与局部相结合的思想,提出了基于一致度、
    发表于 01-02 18:43 0次下载

    分布式大数据不一致性检测

    关系数据库中可能存在数据不一致性现象,关系数据库数据质量的个主要问题是存在违反函数依赖情况,为找出不一致数据需要进行函数依赖冲突检测.集中式数据库中可以通过SQL威廉希尔官方网站 检测不一致情况,
    发表于 01-12 16:29 0次下载

    锂电池组不一致性的原因及危害是怎样的

    锂电池组不一致性的原因及损害,看了就明白!锂电池组电压不一致会发生什么损害?怎么应对锂电池组不一致性的损害?锂电池参数的不一致首要是指容量、内阻、开路电压的
    发表于 03-17 17:39 1.2w次阅读

    锂电池组不一致性的原因是什么,它的危害有哪些

    锂电池组不一致性的原因及损害,看了就明白!锂电池组电压不一致会发生什么损害?怎么应对锂电池组不一致性的损害?锂电池参数的不一致首要是指容量、内阻、开路电压的
    发表于 03-17 17:41 4502次阅读

    封装中管脚与原理图中不一致应该如何解决

    管脚数目一致,管脚名不一致,可按案例图示修改管脚名即可。 PCB 封装中管脚数目缺少,即 PCB 封装管脚数目与原理图中所选用的器件管脚数目要少而导致管脚名不一致报错,处理方式是检查器
    发表于 12-21 15:38 19次下载

    什么是电芯的不一致性?电芯不一致会造成什么后果?

    这些电芯在容量、电压、内阻等方面存在差异的现象。 首先,容量不一致导致电池组充电和放电不平衡。比如在充电过程中,容量大的电芯会充满电后继续接收充电,而容量小的电芯已经充满电,但仍在接收充电,造成了些电芯过
    的头像 发表于 11-06 10:56 3490次阅读

    什么是锂离子电池不一致性?如何提高锂离子电池的一致性?

    以及充放电速率和循环寿命的差异。锂离子电池的不一致性主要由以下几个方面的原因造成: 1. 材料差异:锂离子电池的正负极材料存在制造差异,其中最常见的是锂离子电池正极材料的颗粒大小和分布不均匀,导致充放电反应不一致
    的头像 发表于 11-10 14:49 1877次阅读

    mysql主从复制数据不一致怎么办

    不一致的原因和解决方法。 MySQL主从复制数据不一致的原因 网络延迟:主从之间的网络延迟导致从库在主库执行完并提交的操作之前拉取到的b
    的头像 发表于 11-16 14:35 2398次阅读

    mysql8.0默认字符集是什么

    MySQL 8.0 默认字符集是 utf8mb4。 MySQL 8.0 是当前最新的开源关系型数据库管理系统,由Oracle公司开发和维护。MySQL 8.0 默认
    的头像 发表于 11-16 14:48 1815次阅读

    导致MySQL索引失效的情况以及相应的解决方法

    导致MySQL索引失效的情况以及相应的解决方法  MySQL索引的目的是提高查询效率,但有些情况
    的头像 发表于 12-28 10:01 760次阅读

    电池电压不一致串联后会自己均衡吗

    电池电压不一致串联后会自己均衡吗 电池电压不一致是指串联连接的电池中,各个电池的电压不完全相同。电池串联起来的总电压等于各个电池的电压之和,但是电池串联后,电流会在电池间流动,导致电池之间的电荷分布
    的头像 发表于 01-19 10:32 8600次阅读

    充放电不一致影响超级电容器性能的原因及解决方案

    等方面。本文将详细探讨充放电不一致的原因,并提出相应的解决方案。 首先,充放电不一致的主要原因之是电解质浓度不均匀。超级电容器中的电解质起到传导电荷的作用,而电解质浓度的不均匀会导致
    的头像 发表于 02-03 15:02 1971次阅读