华为云用户手册

  • 原因分析 大部分情况下,distinct是可以转化成等价的group by语句。在MySQL中,distinct关键字的主要作用就是去重过滤。 distinct进行去重的原理是先进行分组操作,然后从每组数据中取一条返回给客户端,分组时有两种场景: distinct的字段全部包含于同一索引:该场景下MySQL直接使用索引对数据进行分组,然后从每组数据中取一条数据返回。 distinct字段未全部包含于索引:该场景下索引不能满足去重分组需要,会用到临时表(首先将满足条件的数据写入临时表中,然后在临时表中对数据进行分组,返回合适的数据)。因为使用临时表会带来额外的开销,所以一般情况下性能会较差。 综上,在使用distinct或group by的时候,尽量在合理的情况下设置可以包含所有依赖字段的索引,优化示例: 没有合适索引,导致需要用到临时表。 有合适的索引,不会使用临时表,直接走索引。
  • 场景描述 业务插入或更新带有emoji表情的数据时,报错Error 1366。 java.sql.SQLException: Incorrect string value: '\xF0\x9F\x90\xB0\xE5\xA4...' for column 'username' at row 1 ;uncategorized SQLException for SQL []; SQL state [HY000]; error code [1366]; Incorrect string value: '\xF0\x9F\x90\xB0\xE5\xA4...' for column 'username' at row 1;
  • 解决方案 将存储emoji表情的字段的字符集修改为utf8mb4。 如果涉及的表和字段比较多,建议把对应表、数据库的编码也设置为utf8mb4。参考命令: ALTER DATABASE database_name CHARACTER SET= utf8mb4 COLLATE= utf8mb4_unicode_ci; ALTERTABLE table_name CONVERTTOCHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTERTABLE table_name MODIFY 字段名 VARCHAR(128) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci; 若对应字段的字符集已经是utf8mb4,则为客户端或MySQL服务端字符集转换问题,将客户端和MySQL服务端的字符集都设置为utf8mb4。
  • 原因分析 关于timestamp字段:MySQL会把该字段插入的值从当前时区转换成UTC时间(世界标准时间)存储,查询时,又将其从UTC时间转化为当前时区时间返回。 timestamp类型字段的时间范围:'1970-01-01 00:00:01' UTC -- '2038-01-19 03:14:07' UTC,详见官方文档。 使用如下命令查看时区: show variables like "%zone%"; 由于使用的是UTC +8时区,所以timestamp字段默认值需要加8小时才是有效范围,即有效支持的范围是从1970-01-01 08:00:01开始。
  • 原因分析 经过排查,是因为参数“sql_mode”设置了NO_FIELD_OPTIONS属性。 sql_mode相关属性介绍: NO_FIELD_OPTIONS:不要在SHOW CREATE TABLE的输出中打印MySQL专用列选项。 NO_KEY_OPTIONS:不要在SHOW CREATE TABLE的输出中打印MySQL专用索引选项。 NO_TABLE_OPTIONS:不要在SHOW CREATE TABLE的输出中打印MySQL专用表选项(例如ENGINE)。
  • Seconds_Behind_Master计算方式 Seconds_Behind_Master即主备复制时延,通过show slave status查询获取。Seconds_Behind_Master计算的伪代码实现如下: if (SQL thread is running) //如果SQL线程启动{ if (SQL thread processed all the available relay log) //IO thread拉取主库Binlog的位置和sql thread应用的relay log相对于主库Binlog的位置相等 { if (IO thread is running) //如果IO线程启动,设置延迟为0 print 0; else //如果IO线程未启动,设置延迟为null print NULL; } else //如果SQL线程没有应用完所有的IO线程写入的event,那么需要计算Seconds_Behind_Master 按公式计算Seconds_Behind_Master的值;} else //如果SQL线程也没有启动,则设置为空值 print NULL; 上述伪代码中,Seconds_Behind_Master的计算公式为: Seconds_Behind_Master = time(0) - last_master_timestamp - clock_diff_with_master 相关变量含义如下: time(0):当前从节点服务器的系统时间。 clock_diff_with_master:从节点的系统时间和主节点服务器系统时间的差值,一般为0。如果主从节点系统时间不一致,那么计算出的从节点复制时延会不准确。 last_master_timestamp:从节点在回放relay log中event过程中计算和更新,该变量在并行复制(MTS)和非并行复制方式下,更新的时机是不同的,默认全部开启并行复制: 并行复制:可以简单理解为,从节点的SQL线程在每个事务执行完成后,更新last_master_timestamp值,其更新是以事务为单位。所以大事务、DDL容易导致主备延迟大,具体请参见主备复制延迟持续增长后自动恢复。 非并行复制:从节点的SQL线程读取了relay log中的事务后,事务未执行前便会更新last_master_timestamp,其更新是以事务为单位。 综上所述,Seconds_Behind_Master的计算公式可以理解为: Seconds_Behind_Master = 当前从节点服务器的系统时间 - 从节点SQL线程处理中事务在主节点的执行时间 - 从节点的系统时间和主节点服务器系统时间的差值
  • 场景描述 RDS for MySQL用户创建表失败,出现如下报错信息: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
  • 故障分析 阿里云RDS Microsoft SQL Server数据库,因存在阻止S SMS 客户端创建用户并且限制授权的“TGR#ON#DATABASE”触发器,因而,只能通过阿里云管理界面创建数据库用户,不支持在SSMS客户端创建用户。华为云支持在SSMS客户端创建数据库用户。 因而,从阿里云迁移到云数据库 RDS for SQL Server,需先禁用阿里云的“TGR#ON#DATABASE”触发器,再在SSMS客户端创建数据库用户并且授权。 登录SSMS客户端。 将“TGR#ON#DATABASE”触发器设置为“disable”,禁用“TGR#ON#DATABASE”触发器。 在SSMS客户端创建用户并授权。 新建的用户授权一定要映射msdb数据库。
  • 主备复制流程 主节点(Master)中有数据更新时,会按照Binlog格式,将更新的操作以event形式写入到主节点的Binlog中。event有多种类型:INSERT、DELETE、UPDATE、QUERY等。 从节点(Slave)连接主节点时,有多少个从节点就会创建多少个Binlog dump线程。 当主节点的Binlog发生变化时,Binlog dump线程会通知所有从节点,并将相应Binlog内容推给从节点。 从节点的I/O thread收到Binlog内容后,会将内容写到本地relay log(中继日志)。 从节点的SQL thread会读取I/O thread写入的relay log,并且根据relay log中的event,回放对应的操作(DML、DDL等)。
  • 原因分析 此类问题与复制时延(Seconds_Behind_Master)的计算方式相关,关于复制时延的计算方式,详见MySQL主备复制原理简介。 出现复制时延尖峰是因为:只读节点IO线程刚好接收到了一个新的Binlog文件,而其SQL线程还没开始回放新的Binlog。导致计算复制时延的last_master_timestamp值还停留在上一个Binlog事务在主机的执行时间,与当前只读节点系统时间time(0)存在时间差,从而出现复制时延尖峰。当SQL线程开始解析新的Binlog时,复制时延立刻回落。 此类问题为偶现现象,不影响实际业务。 下载复制时延飚高回落时间段的Binlog,会发现如下现象: 新的Binlog的第一个事务执行时间与上一个Binlog最后一个事务的结束时间刚好与突增回落的时间差匹配。
  • 原因分析 检查RDS for MySQL的参数“binlog_rows_query_log_events”的值是否设置为1或ON。 目前canal只能支持ROW格式的Binlog增量订阅。 当RDS for MySQL的参数“binlog_rows_query_log_events”的值设置为1或ON时,会在Binlog中产生Rows_query类型的event,此类event非ROW格式,一些场景下,会导致canal出现blank topic问题,引发Binlog解析失败。
  • 解决方案 RDS for MySQL的CAST()和CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值。两者具体的语法如下: CAST(value as type);CONVERT(value, type); 就是CAST(xxx AS 类型), CONVERT(xxx,类型)。 可以转换的类型是有限制的。这个类型可以是以下值其中的一个: 二进制,同带binary前缀的效果 : BINARY; 字符型,可带参数 : CHAR(); 日期 : DATE; 时间: TIME; 日期时间型 : DATETIME; 浮点数 : DECIMAL; 整数 : SIGNED; 无符号整数 : UNSIGNED。
  • 场景描述 canal解析Binlog出现错误,导致拉取Binlog中断,错误信息如下: xxx.otter.canal.parse.exception.CanalParseException: java.lang.NumberFormatException:- Caused by: java.lang.NumberFormatException: - at xxx.fastsql.sql.parser.Lexer.integerValue(Lexer.java:2454)
  • RDS MySQL timeout相关参数简介 MySQL中有多种timeout参数,RDS for MySQL也将相关参数提供给用户设置,如下表: 表1 参数说明 参数名称 修改是否需要重启 参数含义 connect_timeout 否 控制客户端和MySQL服务端在建连接时,服务端等待三次握手成功的超时时间(秒),网络状态较差时,可以调大该参数。 idle_readonly_transaction_timeout 否 空闲的只读事务被kill前的等待时间,以秒为单位。(5.7.23版本之后支持) idle_transaction_timeout 否 空闲事务被kill前的等待时间,以秒为单位。默认值设为0,代表永不kill。(5.7.23版本之后支持) idle_write_transaction_timeout 否 空闲的读写事务被kill前的等待时间,以秒为单位。默认值设为0,代表永不kill。(5.7.23版本之后支持) innodb_lock_wait_timeout 否 放弃事务前,InnoDB事务等待行锁的时间。 innodb_rollback_on_timeout 是 innodb_rollback_on_timeout确定后,事务超时后InnoDB回滚完整的事务。 lock_wait_timeout 否 试图获得元数据锁的超时时间(秒)。 net_read_timeout 否 中止读数据之前从一个连接等待客户端网络包的秒数。 net_write_timeout 否 中止写数据之前等待一个网络包被写入TCP连接的秒数。 interactive_timeout 否 MySQL服务端在关闭交互式连接之前等待活动的秒数。 wait_timeout 否 MySQL服务端在关闭非交互式连接之前等待活动的秒数。 父主题: 参数类
  • 场景1:主库执行了大事务 大事务一般指一个事务中包含大量的数据更新操作,例如一个事务包含几万次DML(insert,update,delete)操作、一条SQL语句批量更新了上万行数据等,大事务往往本身的执行时间很长(分钟级)。当主实例执行了大事务后,会产生大量的Binlog日志,备机或只读节点拉取这些Binlog耗时比一般事务长,且至少需要花费与主实例相同的时间来回放这些事务的更新,从而导致备机或只读节点出现复制延迟。 排查方法: 对于包含大量DML语句的大事务,使用如下命令,找到长时间执行的事务。 select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \G; 对于一条SQL语句执行大量数据的大事务,执行show full processlist,查找是否存在长时间执行的delete或update语句。 分析全量日志或慢日志,检查是否有大事务。 解决方法: 为了保证主从数据的一致性,需要等待大事务执行完成,主备复制延迟才能恢复。 业务侧避免此类大事务,可以将大事务拆分为小事务,分批执行。例如,通过where条件或limit语句限制每次要更新的数据量。
  • 场景2:对无主键表更新 RDS for MySQL的Binlog采用row格式,对每一行的数据更新,都会形成row格式Binlog event记录。例如:一个update语句更新100行数据,那么row格式的Binlog中会形成100行update记录,备机或只读回放时会执行100次单行update。 只读节点和备机在回放主库的Binlog event时,会根据表的主键或者二级索引来检索需要更改的行。如果对应表未创建主键,则会产生大量的全表扫描,从而降低了Binlog日志的应用速度,产生复制延迟。 排查方法: 通过show create table xxx,分析执行慢的update和delete语句对应的表,分析是否有主键。 解决方法: 给无主键表增加主键,给缺少二级索引的表增加索引。
  • 场景4:只读实例等待MDL锁 只读实例上往往有业务流量,如果存在只读长事务正在执行,会阻塞主实例同步过来的相应表的DDL操作,卡在了表MDL锁获取,进而阻塞所有同表的后续Binlog回放,导致复制延迟越来越大。 排查方法: 登录只读节点,使用如下命令,观察是否有长时间执行的事务。 select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \G; 查看只读节点的MDL锁视图,观察是否有MDL锁冲突。 select * from information_schema.metadata_lock_info; 根据MDL锁视图中的线程ID,找到阻塞的session。更多信息,请参见MDL锁视图。 解决方法: kill只读节点上阻塞DDL操作的长事务,或者在业务侧提交该长事务。
  • 原因分析 控制台上修改“long_query_time”参数是全局级别生效,修改完后,后续新建连接会使用最新设置的参数,但是旧连接的“long_query_time”属性值不会被改变,仍然保持旧的值(该案例中是0.1s),所以小于0.2s的慢SQL是在旧连接上产生的。 出现该现象的原因是MySQL机制导致,所以不仅“long_query_time”参数会出现此类问题,其他控制台上可以修改的全局参数,也会发生类似现象:只有新建连接生效,旧连接不生效。
  • 原因分析 查看CPU使用率监控指标,发现在16:08分左右实例的CPU使用率开始飙升到100%,且一直持续在高位线。 图1 CPU使用率 查看QPS、慢SQL数以及活跃连接数监控指标,发现在16:08分左右QPS突增,活跃连接数上涨,最终业务侧有较多的慢SQL产生。 图2 QPS 图3 活跃连接数 图4 慢SQL数 分析业务类型,查看16:08分前左右InnoDB的逻辑读速率有突增,且与慢SQL的速率趋势相似。 图5 InnoDB逻辑读速率 登录实例,查看实话会话,发现大量会话在执行SELECT COUNT(*)。 EXPLAIN确认该SQL的执行计划,发现走全表扫描且单条扫描行数在35万+,其并未走索引。 进一步查看该表的表结构,发现该表仅对字段“is_deleted”添加了一个索引“IDX_XX_USERID”,因此上述查询无索引可选。建议业务侧给字段“idx_user_id”新增索引后,实例在16:37分左右CPU下降到正常水平,业务恢复。
  • 解决方案 建议新上业务时,提前对关键SQL通过EXPLAIN、SQL诊断等工具进行执行计划分析,根据优化建议添加索引,避免全表扫描。 业务量突增的高并发造成CPU占用率高,可以考虑升级实例规格或使用独享型资源避免出现CPU资源争抢,或者创建只读实例进行读写分离减轻主实例负载。 通过show processlist查看当前会话信息来辅助定位:运行状态为Sending data、Copying to tmp table、Copying to tmp table on disk、Sorting result、Using filesort的查询会话可能均包含性能问题。 应急场景可以借助SQL限流以及KILL会话功能来临时kill规避“烂SQL”。
  • 解决方案 针对多值插入方式引起的OOM,建议减少单次插入数据量,分多次插入,且及时断开重连会话以释放内存。可执行show full processlist查看是否有明显占用内存高的会话。 合理设置SESSION级内存参数大小,可大体根据全局内存+会话级内存*最大会话数来预估可能最大的内存。注意开启“performance_schema”也会带来内存开销。 升级实例规格,将内存利用率维持在合理范围,防止业务突增导致实例OOM。
  • 原因分析 查看慢SQL数监控指标,发现实例的慢SQL速率在18:03分开始上涨,且最高值达到700个/秒。 图1 慢SQL数 查看实例的CPU使用率监控指标,发现此时的CPU使用率在88%,并未达到性能瓶颈。 图2 CPU使用率 查看实例的QPS监控指标,在18:03开始上涨到18:05有超过3倍增长,说明此时是业务的高峰期。 图3 QPS 排查磁盘读写吞吐量监控指标,发现磁盘的吞吐量达到350MB/s,达到性能瓶颈。 关于存储性能说明,请参见数据库实例存储类型。 图4 磁盘吞吐量
  • 解决方案 MySQL在读写业务时,查询更新请求的数据页如果不在Buffer Pool中,则需要读写底层存储的数据会产生物理I/O。可优先通过调整“innodb_io_capacity”或“innodb_io_capacity_max”参数来影响刷新脏页和写入缓冲池的速率,防止过高的I/O吞吐。 购买高性能的极速型SSD云盘,或者升级实例内存规格将更多数据缓存到Buffer Pool解决高I/O吞吐问题。
  • 原因分析 查看查询变慢对应的时间段中,实例CPU监控指标并无飙升情况且使用率一直都较低,因此排除了CPU冲高导致查询变慢的可能。 图1 CPU使用率 分析对应时间段该实例的慢日志,该SQL执行快时其扫描行数为百万级,当SQL执行慢时其扫描行数为千万级,与业务确认该表短期内并无大量数据插入,因此推断执行慢是因为未走索引或选错索引。且通过EXPLAIN查看该SQL的执行计划确实是全表扫描。 图2 慢日志 在实例上对该表执行SHOW INDEX FROM检查三个字段的索引区分度(或基数)。 图3 查看索引区分度 可知基数最小的字段“query_date”在联合索引的第一位,基数最大的字段“group_id”在联合索引最后一位,而且原SQL包含对“query_date”字段的范围查询,导致当索引走到“query_date”就会停止匹配,后面两个字段已经无序,无法走索引。所以该SQL本质上只能利用到对“query_date”这一列的索引,而且还有可能因为基数太小,导致优化器成本估计时选择了全表扫描。 业务重新创建了联合索引将“group_id”字段放在第一位,“query_date”字段放在最后一位后,查询耗时符合预期。
  • RDS for MySQL内存说明 RDS for MySQL的内存大体可以分为GLOBAL级的共享内存和SESSION级的私有内存两部分: 共享内存是实例创建时根据参数即分配的内存空间,并且是所有连接共享的。 私有内存用于每个连接到MySQL服务器时才分配各自的缓存,且只有断开连接才会释放。 低效的SQL语句或数据库参数设置不当都可能会导致内存利用率升高,遇到突发业务高峰时,可能会导致云数据库内存OOM(Out Of Memory)。
  • 原因分析 查看内存利用率监控指标,实例的内存使用率在16:30左右率突增,触发OOM后实例重启,内存使用率骤降。 图1 内存利用率 查看该时间段慢SQL数监控指标,确认该时间段慢SQL数量突增。 图2 慢SQL数 查看磁盘吞吐相关指标,发现磁盘此时有大量读写操作。 图3 磁盘吞吐 分析对应时间点的慢日志记录,该时间点有大量的多值批量插入语句,该插入方式会导致每个会话申请较多的SESSION级内存,并发高,很容易引起实例OOM。 图4 慢日志
  • 原因分析 同一条sql语句在数据库中执行第1次和第2次可能会性能差异巨大,这是由数据库的buffer_pool机制决定的: 第1次执行时,数据在磁盘上,称之为冷数据,读取需要一定的耗时。 读取完,数据会被存放于内存的buffer_pool中,称为热数据,读取迅速;对于热数据的访问速度极大的超过冷数据,所以当数据是热数据时,sql语句的执行速度会远快于冷数据。 该场景中,源端数据库中常用的数据一般是热数据,所以访问时速度极快。当数据迁移到云上RDS for MySQL时,第1次执行同样的sql语句,很可能是冷数据,就会访问较慢,但再次访问速度就会得到提升。
  • 原因分析 正常情况下,设置了Binlog过期时间,当Binlog备份至OBS,且超过过期时间后,会自动清理,如果长时间未清理,需考虑是否有其他复制异常因素导致。 排查思路: 查看MySQL的错误日志,查找是否有类似无法purge binlog的日志记录。 2022-01-18T05:39:03.139207+08:00 29 [Warning] file ./mysql-bin.106259 was not purged because it was being readby thread number 27490757 分析是否有本地搭建复制关系、使用canal等工具监听该实例的Binlog,当主库未收到对应Binlog已被从库或工具获取的信息,会导致对应Binlog不被删除,导致Binlog积压。 结合1中的异常binlog purge记录,分析本地从库或canal工具相应日志,排查网络状况等原因确认Binlog未被清理的原因。
  • 场景描述 14点~15点之间数据库出现大量行锁冲突,内核中大量update/insert会话在等待行锁释放,导致CPU使用率达到70%左右,数据库操作变慢。 查看 CES 指标行锁等待个数、MDL锁数量,下图仅供参考: 发生死锁的表: ********* 1. row *********Table: table_test Create Table: CREATE TABLE table_test(...CONSTRAINT act_fk_exe_parent FOREIGN KEY (parent_id_) REFERENCES act_ru_execution (id_) ON DELETE CASCADE,CONSTRAINT act_fk_exe_procdef FOREIGN KEY (proc_def_id_) REFERENCES act_re_procdef (id_),CONSTRAINT act_fk_exe_procinst FOREIGN KEY (proc_inst_id_) REFERENCES act_ru_execution (id_) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT act_fk_exe_super FOREIGN KEY (super_exec_) REFERENCES act_ru_execution (id_) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
  • 解决方案 随着业务数据的增加,原来申请的数据库磁盘容量可能会不足,建议用户扩容磁盘空间,确保磁盘空间足够。 如果原有规格的磁盘已是最大,请先升级规格。 云盘实例可以设置存储空间自动扩容,在实例存储空间达到阈值时,会触发自动扩容。 针对数据空间过大,可以删除无用的历史表数据。 如果实例变为只读状态,您需要先联系客服解除只读状态;如果实例非只读状态,则可以直接执行删除操作。 查看物理文件大小Top50库表,识别可以删除的历史表数据,具体操作请参见容量预估。 可在业务低峰期对碎片率高的表执行optimize优化,以便释放空间: 清理整张表使用DROP或TRUNCATE操作;删除部分数据,使用DELETE操作,如果是执行DELETE操作,需要使用OPTIMIZE TABLE来释放空间。 如果是RDS for MySQL Binlog日志文件占用过多,可以清理本地Binlog日志,来释放磁盘空间。 针对大量排序查询导致的临时文件过大,建议优化SQL查询。 查询数据库慢SQL和Top SQL,分析数据量大,行数多,响应时间长的SQL语句,并进行优化。 您还可以订阅实例健康日报来获取SQL及性能分析结果,包括慢SQL分析、全量SQL分析、性能 & 磁盘分析、性能指标趋势图,当发生风险点时及时收到诊断报告。 具体操作请参见诊断日报。
共100000条