RDS for MySQL 字符序(collation)引发的性能问题

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: RDS for MySQL 字符序引发的 CPU 性能问题

在帮客户排查问题的时候,经常会遇到的 RDS 实例性能问题(比如 RDS 实例 CPU 使用率高),而其中有一类是由于字符集的字符排序规则不一致导致的。从处理的过程中可以看出来,这类问题比较容易出现但不容易定位排查,所以今天通过两个实战案例来分析的下“RDS for MySQL 字符序(collation)引发的性能问题”。


首先介绍下背景知识: 字符集 和 字符序。


1. 字符集(character set)和字符序(collation)

字符集是一组符号和编码,用来保存和解释 MySQL 的字符类型数据,比如 varchar 类型的数据。
字符序是一组在指定字符集中进行字符比较的规则,比如是否忽略大小写,是否按二进制比较字符等等。

2. 字符序基本比较规则

两组字符类型数据进行比较,需要一致的字符集(character set)和 字符序(collation),否则需要进行隐式转换。

3. 实战案例分析

  • 案例分析一:实例 CPU 使用率达到 100%,业务响应时间长,影响使用体验。




问题原因定位到一条普通查询语句:

select 
    aid, ip, adid, openudid
from
    `tab01`
where
    `reg_time` between '2016-10-12 00:00:00' and '2016-10-12 23:59:59'

该语句在上线前通过 MySQL 命令行进行过测试,执行时间在 20 MS(毫秒)左右。
但在生产环境由 PHP Lavravel 框架提交执行需要 20 Sec(秒)以上才可以完成; 大量该类型查询执行导致连接堆积,RDS 实例 CPU 使用率 100%

首先在 MySQL 命令行下,检查表结构:

CREATE TABLE `tab01` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `reg_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `ip` char(15) NOT NULL,
    `aid` bigint(20) NOT NULL,
    `adid` varchar(255) NOT NULL,
    `openudid` varchar(255) NOT NULL,
    PRIMARY KEY (`id`),
    KEY `reg_time` (`reg_time`),
    KEY `aid` (`aid`),
    KEY `adid` (`adid`) USING BTREE
)  ENGINE=InnoDB AUTO_INCREMENT=11964136 DEFAULT CHARSET=utf8

检查执行计划,未见异常:
 
请用户协助捕捉 PHP Laravel 框架提交查询的网络通信过程:


在网络交互过程中,发现应用在连接建立后执行了下面的语句,然后间隔部分其他查询后才执行的上述查询:

set names utf8 collate utf8_unicode_ci;

那么这条命令具体修改了什么,可以通过 MySQL 命令行连接来模拟验证下 :

可以看到,该条命令将连接的字符序(collation_connection)从 utf8_general_ci (默认值)修改为 utf8_unicode_ci ;而表中数据使用的是默认字符序(utf8_general_ci,在表的 create 定义语句中如果没有指定,则使用字符集的默认字符序),两者并不相同。
注:

    RDS for MySQL 支持的字符序可以通过下面的命令获取:

-- 查看 RDS for MySQL 支持的所有字符序
show collation;

-- 查看 RDS for MySQL 支持的某一字符集对应的字符序
show collation like 'utf8%';

 


在修改了字符序后,语句的执行计划就变为全索引扫描


请注意查询的执行成本由 8427 改变为 13771569,增加了 1633 倍。

修改框架的字符序设置后,查询执行时间恢复正常,RDS 实例 CPU 使用率过高的问题解决



案例分析二:RDS 实例 CPU 使用率波动性打高,导致业务卡顿。




定位到下面的查询,检查语句执行计划,发现优化器对表 tab03 选择了全表扫描的方式来访问数据

explain
SELECT 
    r.org_no,
    r.cp_no,
    r.NAME cp_name
    FROM
        tab02 r
    LEFT JOIN tab03 a ON r.cp_no = a.cp_no
        AND A.SHARD_NO =  r.shard_no
    WHERE
        r.shard_no = '41401'
            AND r.org_no LIKE '41401%'
            limit 100;
+----+-------------+-------+------+---------------------------------------------+-------------------------+---------+-------+-------+------------------------------------------------+
| id | select_type | table | type | possible_keys                               | key                     | key_len | ref   | rows  | Extra                                          |
+----+-------------+-------+------+---------------------------------------------+-------------------------+---------+-------+-------+------------------------------------------------+
| 1  | SIMPLE      | r     | ref  | auto_shard_key_shard_no                     | auto_shard_key_shard_no | 99      | const | 30637 | Using index condition; Using where             |
| 1  | SIMPLE      | a     | ALL  | R_CP_TAB03_UK,auto_shard_key_shard_no       |                         |         |       | 13221 | Range checked for each record (index map: 0xA) |
+----+-------------+-------+------+---------------------------------------------+-------------------------+---------+-------+-------+------------------------------------------------+
共返回 2 行记录,花费 2.23 ms.

而表 tab03 上有合适的唯一索引 R_CP_TAB03_UK

CREATE TABLE `tab03` (
    `TERMINAL_ID` bigint(16) NOT NULL,
    `CP_NO` varchar(16) NOT NULL,
    `CP_NAME` varchar(256) DEFAULT NULL,
    `DATA_SRC` varchar(8) DEFAULT NULL,
    `IS_DIRECT` varchar(8) DEFAULT NULL,
    `SHARD_NO` varchar(32) DEFAULT NULL,
    PRIMARY KEY (`TERMINAL_ID`),
    UNIQUE KEY `R_CP_TAB03_UK` (`CP_NO`),
    KEY `auto_shard_key_shard_no` (`SHARD_NO`)
)  ENGINE=InnoDB DEFAULT CHARSET=utf8

而且 Extra 字段给出的是 Range checked for each record(index map:0xA),说明存在潜在可以使用的索引,但由于某种原因无法使用

查看表 tab02 的定义:

CREATE TABLE `tab02` (
    `cp_no` varchar(32)CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
    `name` varchar(512)CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
    `data_src` varchar(16)CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
    `shard_no` varchar(32) DEFAULT NULL,
    PRIMARY KEY (`cp_no`),
    KEY `auto_shard_key_shard_no` (`shard_no`),
    KEY `INDX_TAB02_NAME` (`name` (255))
)  ENGINE=InnoDB DEFAULT CHARSET=utf8

表 tab02 的 cp_no 字段采用 utf8_bin(按二进制比较,不忽略大小写) 字符序,而表 tab03 的 cp_no 字段采用 utf8_general_ci(默认)字符序,两者字符序不匹配,因此无法使用正确的索引。

修改表 tab03 的 cp_no 字段字符序为 utf8_bin,执行计划恢复正常,RDS 实例 CPU 波动性打高的问题解决

7bfc4b8da320c9cc226f12dc68bfba4e5b4a02a7


从以上的案例可以看到,正确的执行计划相较调整前的执行计划效率大约提升了 13221 倍。字符序不仅仅可以导致 CPU 使用率问题,也可能引入比如 IOPS 使用率高 等其他问题。因此建议应用开发保持统一的字符集和字符序使用规范,避免规范不统一引入性能问题。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
9天前
|
SQL 存储 关系型数据库
"MySQL增列必锁表?揭秘InnoDB在线DDL,让你的数据库操作飞一般,性能无忧!"
【8月更文挑战第11天】在数据库领域,MySQL凭借其稳定高效的表现深受开发者喜爱。对于是否会在给数据表添加列时锁表的问题,MySQL的行为受版本、存储引擎等因素影响。从5.6版起,InnoDB支持在线DDL,可在改动表结构时保持表的可访问性,避免长时间锁表。而MyISAM等则需锁表完成操作。例如,在使用InnoDB的表上运行`ALTER TABLE users ADD COLUMN email VARCHAR(255);`时,通常不会完全锁表。虽然在线DDL提高了灵活性,但复杂操作或大表变更仍可能暂时影响性能。因此,进行结构变更前应评估其影响并择机执行。
31 6
|
6天前
|
缓存 NoSQL Redis
一天五道Java面试题----第九天(简述MySQL中索引类型对数据库的性能的影响--------->缓存雪崩、缓存穿透、缓存击穿)
这篇文章是关于Java面试中可能会遇到的五个问题,包括MySQL索引类型及其对数据库性能的影响、Redis的RDB和AOF持久化机制、Redis的过期键删除策略、Redis的单线程模型为何高效,以及缓存雪崩、缓存穿透和缓存击穿的概念及其解决方案。
|
9天前
|
存储 关系型数据库 MySQL
"揭秘!MySQL为何独宠B+树?跳表再牛,也敌不过这性能王者的N重诱惑!"
【8月更文挑战第11天】MySQL作为主流关系型数据库,优选B+树而非跳表作为索引结构,基于其对范围查询的支持、低磁盘I/O开销及事务处理能力。B+树叶节点构成有序链表,利于范围查询;较矮的树形结构减少了磁盘访问次数;支持多版本并发控制,保障事务ACID特性。而跳表在线性扫描范围查询时效率低,难以高效实现事务管理,且额外指针增加空间消耗。示例代码展示了B+树节点分裂过程,突显其内部机制。综上,B+树为MySQL提供了高性能、可靠的数据存储与检索能力。
22 4
|
7天前
|
关系型数据库 MySQL
MySQL——删除指定字符
MySQL——删除指定字符
16 1
|
13天前
|
关系型数据库 MySQL OLTP
性能工具之 MySQL OLTP Sysbench BenchMark 测试示例
【8月更文挑战第6天】使用 pt-query-digest 工具分析 MySQL 慢日志性能工具之 MySQL OLTP Sysbench BenchMark 测试示例
53 0
性能工具之 MySQL OLTP Sysbench BenchMark 测试示例
|
21天前
|
关系型数据库 MySQL Serverless
函数计算产品使用问题之调用RDS MySQL的步骤是怎样的
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
26天前
|
存储 负载均衡 关系型数据库
面试题MySQL问题之通过配置FastDFS提高性能如何解决
面试题MySQL问题之通过配置FastDFS提高性能如何解决
33 1
|
26天前
|
SQL 关系型数据库 MySQL
mysql性能调优:EXPLAIN命令21
【7月更文挑战第21天】掌握SQL性能调优:深入解析EXPLAIN命令的神奇用法!
32 1
|
5天前
|
SQL 关系型数据库 MySQL
MySql⭐一、配置MySql数据库,并创建一个表单
MySql⭐一、配置MySql数据库,并创建一个表单
|
12天前
|
SQL 关系型数据库 MySQL
MySQL运行在docker容器中会损失多少性能
MySQL运行在docker容器中会损失多少性能

热门文章

最新文章