力荐:一条update语句引发的“血案”

2023-12-07 19:40

本文主要是介绍力荐:一条update语句引发的“血案”,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


有一次得到应用同学的反馈,有一个前端应用登录很慢,已经开始影响业务登录了,稍后DBA介入,发现是由于CPU使用率过高导致,为了能够缓解问题和进一步分析,做了一些改进措施,最后问题得到了化解,但是对于这个问题后续也进行了更多的分析,也算是事后诸葛亮吧。

 

整个分享的思路如下:

问题背景

提出疑问

问题的对比测试

问题的验证

问题总结

 

 

 

问题背景  

 

查看慢日志的情况如下:   

 

20160523104236648.png


两个查询的统计信息如下,可以看到平均执行时间竟然都在40s左右。

 

20160523104225269.png 

涉及的SQL语句如下,这个也是当时从慢日志中得到的。

 

20160523104214391.png

 

相关的表只有一个,表结构如下:

 20160523104203959.png

 

整个调用过程的要点是下面的形式,里面有一个update操作,字段APNS_PUSH_ID为varchar

 

20160523104151649.png

 

其实单独运行的语句就类似下面的形式:


20160523104142749.png 

这样一个update语句竟然很慢,着实感到很奇怪,因为单独执行,查看执行计划是没有问题的。

 

 

提出疑问  

 

对于这个问题的疑问如下:

 

1、对于字符型字段作为索引,目前来看没有很直接的原因发现字符型索引和数字型索引存在巨大的差别。从后来我单独得到的执行计划和后来复现情况来看,没有发现存在很巨大的差别。

 

2、对于慢日志中得到的语句,看到内部已经做了转换。

 

20160523104133365.png

 

而对于这种转换,可能关注点都在NAME_CONST这个部分,在查看了一些资料之后,发现在其他版本和环境中,主要是和字符集转换有关,但是单独执行上面的转换语句,查看执行计划没有任何问题。

 

3、在5.1版本中发现了相应的bug描述,但是目前的环境是在5.6,所以问题应该已经得到修复。

 

我希望得到一些确切的信息,能够复现,能够找到一些相关的bug或者相关的解决方案。

 

 

问题的对比测试  

 

 

我找了套环境尝试复现这个问题,我把表里的数据复制到一个测试环境,然后写了下面的存储过程来复现和对比。

 

20160523104122879.png
 

测试前,保证handler是初始化状态

 

20160523104114181.png

 

然后运行存储过程,其实这个过程就是当时问题发生时的一个调用环节。

 

20160523104105891.png

 

查看Handler的状态,可以看到Handler_read_next的值极高,其实这是一个全表扫描。

 

20160523104054722.png
 

而如果单独执行同样的sql语句。

 

20160523104044141.png
 

查看Handler的情况,Handler_read_rnd_next为0,很显然是一个索引扫描。

 

20160523104034742.png
 

如果查看单独update语句的执行计划,是看不到太多的明细信息的。

 

20160523104025847.png

 

我们可以打开trace,MySQL 5.6以后有一个特性,可以试试。

  

20160523104012439.png

 

可以看到内部做了字符集的转换,而转换的过程其实也可以这么理解,convert(`push_list_s`.`APNS_PUSH_ID` using utf8)这个操作是把全表的APNS_PUSH_ID先做转换和push_id做匹配,这也就无形中导致了全表扫描。

 

20160523104002856.png
20160523103949569.png

 

 

执行单个语句,查看trace的情况。

 

20160523103934660.png
 

 可以看到解析的时候是在做键值的匹配。

  20160523103924682.png

20160523103906784.png

 

对于这个问题,经过这样的分析测试,会发现在存储过程中和单独执行的场景中还是存在差别的,而问题的关键就在于字段APNS_PUSH_ID的字符集,

 

20160523103850958.png 

所以唯一的差别就在于字符集,MySQL对于字符集的支持非常灵活,数据库级,表级,字段级别都可以定制,而对于这个问题的直接修复,就是统一字段” APNS_PUSH_ID”的字符集为表级的UTF8。

 

 

问题的验证  

 

问题的验证步骤如下:

 

20160523103839424.png

 

统一字符集之后,再次执行,就会发现效率就会大大提高。

 

20160523103827314.png

 

而且MySQL的回复如下:

Problem is that the stored routine does not explicitly declare the charset of the parameter that is passed to the stored routine. It must match the column's charset to which you're comparing it to. 

 

 

问题总结  

 

其实对于问题还是需要刨根问底,找到了问题的症结,就会让我们在处理问题的时候更加坦然。我自己也尝试从Oracle的对比中得到一些解决问题的思路,但是Oracle对于字符集的支持是统一管理方式的,所以也是无果而终,不过这种对比方式给了我一些思路。对于字符集的设定,虽然灵活方便,但是也要使用统一得当。

 

 作者介绍  杨建荣

 

  • 【DBAplus社群】联合发起人;

  • Oracle ACE-A、YEP成员,现就职于搜狐畅游,拥有6年以上的数据库开发和运维经验,曾任amdocs DBA,擅长电信数据业务,数据库迁移和性能调优;

  • 拥有Oracle 10g OCP,OCM,MySQL OCP认证,对shell,ava有一定的功底,曾在2015年数据库大会进行关于数据迁移和升级的主题分享,现在每天仍在孜孜不倦的进行技术分享,每天通过微信,技术博客共享,已连续坚持800多天。


本文来自云栖社区合作伙伴"DBAplus",原文发布时间:2016-05-23

这篇关于力荐:一条update语句引发的“血案”的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/467113

相关文章

Mysql常见的SQL语句格式及实用技巧

《Mysql常见的SQL语句格式及实用技巧》本文系统梳理MySQL常见SQL语句格式,涵盖数据库与表的创建、删除、修改、查询操作,以及记录增删改查和多表关联等高级查询,同时提供索引优化、事务处理、临时... 目录一、常用语法汇总二、示例1.数据库操作2.表操作3.记录操作 4.高级查询三、实用技巧一、常用语

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指

SQL BETWEEN 语句的基本用法详解

《SQLBETWEEN语句的基本用法详解》SQLBETWEEN语句是一个用于在SQL查询中指定查询条件的重要工具,它允许用户指定一个范围,用于筛选符合特定条件的记录,本文将详细介绍BETWEEN语... 目录概述BETWEEN 语句的基本用法BETWEEN 语句的示例示例 1:查询年龄在 20 到 30 岁

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Mybatis Plus JSqlParser解析sql语句及JSqlParser安装步骤

《MybatisPlusJSqlParser解析sql语句及JSqlParser安装步骤》JSqlParser是一个用于解析SQL语句的Java库,它可以将SQL语句解析为一个Java对象树,允许... 目录【一】jsqlParser 是什么【二】JSqlParser 的安装步骤【三】使用场景【1】sql语

sql语句字段截取方法

《sql语句字段截取方法》在MySQL中,使用SUBSTRING函数可以实现字段截取,下面给大家分享sql语句字段截取方法,感兴趣的朋友一起看看吧... 目录sql语句字段截取sql 截取表中指定字段sql语句字段截取1、在mysql中,使用SUBSTRING函数可以实现字段截取。例如,要截取一个字符串字

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

MySQL 中的 LIMIT 语句及基本用法

《MySQL中的LIMIT语句及基本用法》LIMIT语句用于限制查询返回的行数,常用于分页查询或取部分数据,提高查询效率,:本文主要介绍MySQL中的LIMIT语句,需要的朋友可以参考下... 目录mysql 中的 LIMIT 语句1. LIMIT 语法2. LIMIT 基本用法(1) 获取前 N 行数据(

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL