百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

MySQL进阶五之海量数据下修改表结构事故复盘[上]

wptr33 2025-02-13 14:34 23 浏览

事故场景


我们开发的阅读快应用在一些投放渠道做推广,用户点击广告素材会快速进入快应用,如果用户第一次打开快应用,则需要为用户自动注册为新用户。但目前的User表数据接近1亿条记录,创建新用户涉及好几张用户基本信息表,导致用户体验不佳。

目前设计方案是使用雪花算法快速生成用户ID,并返回给快应用。采用MQ的削峰填谷异步保存用户信息数据提高用户体验,但我们的User表主键类型是int , 需要升级为 BIGINT(20)。我们考虑到修改字段类型会锁表,在凌晨1点开始执行相关升级SQL语句。

ALTER TABLE `user` 
CHANGE COLUMN `id` `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID' ;

执行以上SQL,总耗时60多分钟,期间User表数据无法更新,且造成长时间主从延迟

■【腾讯云可观测平台告警】

您好!您账号(账号ID: ********,昵称: ********)的腾讯云可观测平台告警持续触发

告警内容: 云数据库-MySQL-主机监控 | 主从延迟时间 > 10 秒

当前数据: 3762 秒 (主从延迟时间)

告警对象: ********(实例名:*****-prod_ro_1,IP地址:127.0.0.45:3306),实例类型:ro

项目|地域: 默认项目 | 北京

告警策略: mysql数据库监控报警

触发时间: 2024-02-27 02:17:00 (UTC+08:00)

持续时间: 1小时0分钟

您可以登录腾讯云可观测平台控制台查看告警详情,或在腾讯云助手小程序查看告警详情

事故发生后,我们进行了复盘,并查询相关资料,了解到 MySQL数据库 Online DDL 目前主流的有三种工具:

  • 原生 Online DDL;
  • pt-osc(online-schema-change),
  • gh-ost

本文主要讲解 MySQL 原生 Online DDL的使用。

什么是Online DDL?

什么是Online DDL?在了解Online DDL之前,我们先来了解一下什么是DDL。说DDL,就不得不提一下它的另外两个兄弟:DML和DCL。

DDL:Data Definition Language,即数据定义语言,用来定义数据的语句。包括:新建、修改、删除等;相关的命令有:CREATE,ALTER,DROP等。

DML:Data Manipulation Language,即数据操作语言,即处理数据库中数据的操作就是DML,包括:选取,插入,更新,删除等;相关的命令有:SELECT,INSERT,UPDATE,DELETE,还有 LOCK TABLE。

DCL:Data Control Language,数据控制语言,用来定义数据访问控制的语句。例如我们平时的grant,revoke等。

我们可以认为:

  • CREATE,ALTER ,DROP,TRUNCATE,定义相关的命令就是DDL;
  • SELECT,INSERT,UPDATE,DELETE,操作处理数据的命令就是DML;

DDL、DML区别:

  • DML操作是可以手动控制事务的开启、提交和回滚的。
  • DDL操作是隐性提交的,不能rollback,一定要谨慎哦!

而Online DDL是指在线的数据定义语言,所谓的在线是指:数据表在不停止服务的情况下来执行我们的DDL语句,即表在应用DDL语句的时候,仍然可以提供读写的服务。

InnoDB and Online DDL

MySQL Online DDL 官方文档

https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl.html

在线DDL功能提供了对即时和就地表更改以及并发DML的支持。此功能的优点包括:

1、在繁忙的生产环境中提高了响应能力和可用性,在这种环境中,不会出现使表在几分钟或几小时内不可用。

2、对于就地操作,可以使用LOCK子句在DDL操作期间调整性能和并发性之间的平衡。

3、与表复制方法相比,磁盘空间使用率和I/O开销更少。

通常,您不需要做任何特殊的事情来启用在线DDL。默认情况下,MySQL会在允许的情况下立即或就地执行操作,并尽可能少地锁定。

ALTER TABLE tbl_name 
ADD PRIMARY KEY (column), 
ALGORITHM=INPLACE, LOCK=NONE;

其中的ALGORITHM有如下选项

  • INPLACE:替换:直接在原表上面执行DDL的操作。表示执行DDL的过程中不发生表拷贝,过程中允许并发执行DML(INPLACE不需要像COPY一样占用大量的磁盘I/O和CPU,减少了数据库负载。同时减少了buffer pool的使用,避免 buffer pool 中原有的查询缓存被大量删除而导致的性能问题)。
  • COPY:复制:使用一种临时表的方式,克隆出一个临时表,在临时表上执行DDL,然后再把数据导入到临时表中,在重命名等。这期间需要多出一倍的磁盘空间来支撑这样的 操作。执行期间,表不允许DML的操作。
  • DEFAULT:默认方式,由MySQL自己选择,优先使用INPLACE的方式。

其中的LOCK有如下选项

  • SHARE:共享锁,执行DDL的表可以读,但是不可以写。
  • NONE:没有任何限制,执行DDL的表可读可写。
  • EXCLUSIVE:排它锁,执行DDL的表不可以读,也不可以写。
  • DEFAULT:默认值,也就是在DDL语句中不指定LOCK子句的时候使用的默认值。如果指定LOCK的值为DEFAULT,那就是交给MySQL子句去决定锁还是不锁表。不建议使用,如果你确定你的DDL语句不会锁表,你可以不指定lock或者指定它的值为default,否则建议指定它的锁类型。

执行DDL操作时,ALGORITHM选项可以不指定,这时候MySQL按照INSTANT、INPLACE、COPY的顺序自动选择合适的模式。也可以指定ALGORITHM=DEFAULT,也是同样的效果。如果指定了ALGORITHM选项,但不支持的话,会直接报错。

注意:在执行Online DDL之前,要在非业务高峰期去执行,并要确认待执行的表上面没有未提交的事务、锁等信息。

Copy和Inplace算法

Copy方式:

  1. 按照原表定义创建一个新的临时表;
  2. 对原表加写锁(禁止DML,允许select);
  3. 在步骤1 建立的临时表执行 DDL;
  4. 将原表中的数据 copy 到临时表;
  5. 释放原表的写锁;
  6. 将原表删除,并将临时表重命名为原表。
  7. 从上可见,采用 copy 方式期间需要锁表,禁止DML,因此是非Online的。比如:删除主键、修改列类型、修改字符集,这些操作会导致行记录格式发生变化(无法通过全量 + 增量实现 Online)。

Inplace方式:

在原表上进行更改,不需要生成临时表,不需要进行数据copy的过程。根据是否行记录格式,又可分为两类:

  • rebuild:需要重建表(重新组织聚簇索引)。比如 optimize table、添加索引、添加/删除列、修改列 NULL/NOT NULL 属性等;
  • no-rebuild:不需要重建表,只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。

对于 rebuild 方式实现 Online 是通过缓存 DDL 期间的 DML,待 DDL 完成之后,将 DML 应用到表上来实现的。例如,执行一个 alter table A engine=InnoDB; 重建表的 DDL 其大致流程如下:

  1. 建立一个临时文件,扫描表 A 主键的所有数据页;
  2. 用数据页中表 A 的记录生成 B+ 树,存储到临时文件中;
  3. 生成临时文件的过程中,将所有对 A 的操作记录在一个日志文件(row log)中;
  4. 临时文件生成后,将日志文件中的操作应用到临时文件,得到一个逻辑数据上与表 A 相同的数据文件;
  5. 用临时文件替换表 A 的数据文件。

说明:

  1. 在 copy 数据到新表期间,在原表上是加的 MDL 读锁(允许 DML,禁止 DDL);
  2. 在应用增量期间对原表加 MDL 写锁(禁止 DML 和 DDL);
  3. 根据表 A 重建出来的数据是放在 tmp_file 里的,这个临时文件是 InnoDB 在内部创建出来的,整个 DDL 过程都在 InnoDB 内部完成。对于 server 层来说,没有把数据挪动到临时表,是一个原地操作,这就是”inplace”名称的来源。

使用Inplace方式执行的DDL,发生错误或被kill时,需要一定时间的回滚期,执行时间越长,回滚时间越长。
使用Copy方式执行的DDL,需要记录过程中的undo和redo日志,同时会消耗buffer pool的资源,效率较低,优点是可以快速停止。
不过并不是所有的 DDL 操作都能用 INPLACE 的方式执行,具体的支持情况可以在(在线 DDL 操作) 中查看。

官网支持列表:

Operation

Instant

In Place

Rebuilds Table

Permits Concurrent DML

Only Modifies Metadata

Adding a column

Yes*

Yes

No*

Yes*

Yes

Dropping a column

Yes*

Yes

Yes

Yes

Yes

Renaming a column

Yes*

Yes

No

Yes*

Yes

Reordering columns

No

Yes

Yes

Yes

No

Setting a column default value

Yes

Yes

No

Yes

Yes

Changing the column data type

No

No

Yes

No

No

Extending VARCHAR column size

No

Yes

No

Yes

Yes

Dropping the column default value

Yes

Yes

No

Yes

Yes

Changing the auto-increment value

No

Yes

No

Yes

No*

Making a column NULL

No

Yes

Yes*

Yes

No

Making a column NOT NULL

No

Yes*

Yes*

Yes

No

Modifying the definition of an ENUM or SET column

Yes

Yes

No

Yes

Yes

栗子

添加索引语法

ALTER TABLE `table_name` 
ADD INDEX `index_name`(`a`,`b`), 
ALGORITHM=INPLACE, LOCK=NONE;

下面例子是给创意的记录表添加索引的例子[creative_date表数据是200W],执行SQL

ALTER TABLE `creative_date` 
ADD INDEX `idx_advertiserId_createTime` (`advertiser_id` ASC, `create_time` ASC),
ALGORITHM=INPLACE, LOCK=NONE;

Action

Response

Duration/Fetch Time

执行SQL

row(s) affected Records: 0

Duplicates: 0

Warnings: 0

6.165 sec

  1. QueryOK,2671168 rows affected(1min35.54 sec):这样的语句表示:执行速度明显慢很多,并且表中的数据被重新构建。
  2. QueryOK,0rows affected(6.165 sec):执行速度有点慢,但是没有copy表中的数据到临时表中,也就是没有用到临时表。
  3. QueryOK,0rows affected(0.07 sec):执行速度很快,没有影响到表中已经存在的数据。

上述的3种情况中,第一种是最不理想的,最后一种是最理想的。如果是上诉情况第1种情况,我们就需要好好的衡量一下我们的Online DDL语句,指定一个可行的执行计划,避免主从不同步的问题发现。此时可以考虑在session级别关闭binlog日志的记录功能,然后在每一个数据库节点上都执行一遍DDL语句,避免用binlog去做数据同步而产生的主从延迟。

相关推荐

MySQL进阶五之自动读写分离mysql-proxy

自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...

Postgres vs MySQL_vs2022连接mysql数据库

...

3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?

引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...

一文由浅入深带你完全掌握MySQL的锁机制原理与应用

本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...

验证Mysql中联合索引的最左匹配原则

后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...

MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)

目录1.索引基础...

你会看 MySQL 的执行计划(EXPLAIN)吗?

SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...

MySQL 从入门到精通(四)之索引结构

索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...

mysql总结——面试中最常问到的知识点

mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...

mysql总结——面试中最常问到的知识点(2)

首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...

MySQL基础全知全解!超详细无废话!轻松上手~

本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...

深入剖析 MySQL 中的锁机制原理_mysql 锁详解

在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...

Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析

引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...

MySQL基础篇:DQL数据查询操作_mysql 查

一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...

MySql:索引的基本使用_mysql索引的使用和原理

一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...