小红书Java面试被问:Online DDL的INSTANT、INPLACE、COPY算法差异

一、Online DDL 演进概述

1. MySQL Online DDL发展历程

text

复制

下载

复制代码
MySQL DDL算法演进:
┌─────────────────────────────────────────────────────────────┐
│ MySQL 5.6 (2013) │ MySQL 5.7 (2015) │ MySQL 8.0 (2018+)    │
├─────────────────────────────────────────────────────────────┤
│ 引入Online DDL概念    │ 增强INPLACE算法     │ 引入INSTANT算法      │
│ 支持部分操作的在线执行 │ 减少重建表场景      │ 秒级添加列/索引      │
│ COPY算法为主         │ 支持在线重命名索引   │ 支持更多在线操作     │
└─────────────────────────────────────────────────────────────┘

2. 三种算法核心对比

特性 INSTANT INPLACE COPY
执行速度 毫秒级 中等
阻塞写 不阻塞 短暂阻塞(元数据锁) 阻塞
空间需求 极小 需要临时空间 双倍空间
日志量 最少 中等 最多
适用版本 MySQL 8.0.12+ MySQL 5.6+ 所有版本
回滚难度 容易 中等 困难

二、INSTANT算法详解

1. INSTANT算法原理

1.1 实现机制

sql

复制

下载

复制代码
-- MySQL 8.0.12+ 引入的INSTANT算法核心原理:
-- 1. 元数据变更:仅修改数据字典,不修改数据行
-- 2. 版本兼容:通过行格式兼容新旧模式
-- 3. 延迟应用:查询时动态解析列信息

-- 查看表是否支持INSTANT
SHOW CREATE TABLE users\G
-- 结果中的"ROW_FORMAT=DYNAMIC"支持INSTANT

-- 查询INSTANT列信息
SELECT * FROM information_schema.innodb_tables 
WHERE name LIKE '%users%';

-- 查看INSTANT添加的列
SELECT * FROM information_schema.innodb_columns 
WHERE table_name = 'users' AND has_default = 1;
1.2 内存数据结构

c

复制

下载

复制代码
// InnoDB内部数据结构(简化)
struct dict_table_t {
    // 表元数据
    char* name;
    uint32_t id;
    
    // INSTANT相关字段
    uint32_t instant_cols;      // INSTANT添加的列数
    uint32_t total_cols;        // 总列数
    uint32_t n_instant_nullable;// 可空INSTANT列数
    
    // 列信息数组
    dict_col_t* cols;
};

// 行格式支持
enum row_format_t {
    REDUNDANT,      // ❌ 不支持INSTANT
    COMPACT,        // ✅ 支持INSTANT (8.0.20+)
    DYNAMIC,        // ✅ 支持INSTANT
    COMPRESSED      // ✅ 支持INSTANT
};

2. INSTANT支持的操作

2.1 支持的操作列表

sql

复制

下载

复制代码
-- 1. 添加列(最常用)
ALTER TABLE users 
ADD COLUMN middle_name VARCHAR(50) DEFAULT '' COMMENT '中间名',
ALGORITHM=INSTANT;

-- 2. 删除列(8.0.29+)
ALTER TABLE users 
DROP COLUMN middle_name,
ALGORITHM=INSTANT;

-- 3. 重命名列(8.0.28+)
ALTER TABLE users 
RENAME COLUMN username TO account_name,
ALGORITHM=INSTANT;

-- 4. 设置列默认值
ALTER TABLE users 
ALTER COLUMN status SET DEFAULT 1,
ALGORITHM=INSTANT;

-- 5. 删除列默认值
ALTER TABLE users 
ALTER COLUMN status DROP DEFAULT,
ALGORITHM=INSTANT;

-- 6. 修改ENUM/SET值(8.0.26+)
ALTER TABLE users 
MODIFY COLUMN role ENUM('user','admin','superadmin') DEFAULT 'user',
ALGORITHM=INSTANT;

-- 7. 修改索引可见性(8.0+)
ALTER TABLE users 
ALTER INDEX idx_email INVISIBLE,
ALGORITHM=INSTANT;
2.2 INSTANT限制条件

sql

复制

下载

复制代码
-- ❌ 不支持INSTANT的场景

-- 1. 表空间限制
CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.ibd' ENGINE=INNODB;
CREATE TABLE t1 (id INT) TABLESPACE ts1;
ALTER TABLE t1 ADD COLUMN c1 INT, ALGORITHM=INSTANT; -- 失败

-- 2. 压缩表(某些版本)
CREATE TABLE t1 (id INT) ROW_FORMAT=COMPRESSED;
ALTER TABLE t1 ADD COLUMN c1 INT, ALGORITHM=INSTANT; -- 可能失败

-- 3. 临时表
CREATE TEMPORARY TABLE tmp (id INT);
ALTER TABLE tmp ADD COLUMN c1 INT, ALGORITHM=INSTANT; -- 失败

-- 4. 全文索引表
CREATE TABLE t1 (id INT, content TEXT, FULLTEXT(content));
ALTER TABLE t1 ADD COLUMN c1 INT, ALGORITHM=INSTANT; -- 失败

-- 5. 分区表(部分操作)
CREATE TABLE t1 (id INT) PARTITION BY HASH(id) PARTITIONS 4;
ALTER TABLE t1 ADD COLUMN c1 INT, ALGORITHM=INSTANT; -- 可能失败

3. INSTANT性能基准测试

sql

复制

下载

复制代码
-- 性能对比测试
CREATE TABLE test_instant (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(255)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

-- 插入100万数据
INSERT INTO test_instant(data) 
SELECT UUID() FROM information_schema.columns c1, information_schema.columns c2 
LIMIT 1000000;

-- 测试INSTANT添加列
SET @start = NOW(6);
ALTER TABLE test_instant 
ADD COLUMN new_col INT DEFAULT 0,
ALGORITHM=INSTANT;
SET @end = NOW(6);
SELECT TIMESTAMPDIFF(MICROSECOND, @start, @end)/1000 as instant_ms;

-- 测试INPLACE添加列
SET @start = NOW(6);
ALTER TABLE test_instant 
ADD COLUMN new_col2 INT DEFAULT 0,
ALGORITHM=INPLACE;
SET @end = NOW(6);
SELECT TIMESTAMPDIFF(MICROSECOND, @start, @end)/1000 as inplace_ms;

-- 测试COPY添加列
SET @start = NOW(6);
ALTER TABLE test_instant 
ADD COLUMN new_col3 INT DEFAULT 0,
ALGORITHM=COPY;
SET @end = NOW(6);
SELECT TIMESTAMPDIFF(MICROSECOND, @start, @end)/1000 as copy_ms;

-- 典型结果:
-- INSTANT: 10-100ms
-- INPLACE: 5-30秒 (取决于数据量)
-- COPY: 30-300秒 (取决于数据量)

三、INPLACE算法详解

1. INPLACE算法原理

1.1 执行流程

sql

复制

下载

复制代码
-- INPLACE算法三阶段执行
-- 阶段1: Prepare(准备)
--   1. 创建临时frm文件
--   2. 申请MDL锁(排他锁)
--   3. 分配临时文件空间

-- 阶段2: Execute(执行)
--   1. 在InnoDB内部重建表
--   2. 应用在线日志记录DML
--   3. 增量构建索引

-- 阶段3: Commit(提交)
--   1. 应用积压的DML
--   2. 重命名临时文件
--   3. 释放MDL锁

-- 查看INPLACE执行进度(MySQL 8.0+)
SELECT * FROM performance_schema.threads 
WHERE PROCESSLIST_COMMAND = 'Alter table'\G

-- 监控INPLACE进度
SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED,
       (WORK_COMPLETED/WORK_ESTIMATED)*100 as progress_pct
FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE '%stage/innodb/alter%';
1.2 INPLACE内存管理

c

复制

下载

复制代码
// InnoDB内部排序缓冲区
struct merge_buf_t {
    ulint buf_size;            // 排序缓冲区大小
    ulint n_recs;              // 记录数
    byte* buf;                 // 缓冲区指针
};

// Online DDL参数配置
SET GLOBAL innodb_sort_buffer_size = 67108864;  -- 64MB
SET GLOBAL innodb_online_alter_log_max_size = 134217728;  -- 128MB
SET GLOBAL innodb_temp_data_file_path = 'ibtmp1:12M:autoextend';

// 监控临时空间
SELECT * FROM information_schema.INNODB_TEMP_TABLE_INFO;
SHOW STATUS LIKE 'Innodb_os_log%';

2. INPLACE支持的操作

2.1 完整的INPLACE操作列表

sql

复制

下载

复制代码
-- ✅ 支持INPLACE的操作

-- 1. 添加/删除二级索引(最常用)
ALTER TABLE users 
ADD INDEX idx_email (email),
ALGORITHM=INPLACE,
LOCK=NONE;  -- 允许并发DML

ALTER TABLE users 
DROP INDEX idx_email,
ALGORITHM=INPLACE,
LOCK=NONE;

-- 2. 重建表优化
ALTER TABLE users 
ENGINE=InnoDB,
ALGORITHM=INPLACE;  -- MySQL 5.6+支持

-- 3. 修改列类型(部分支持)
ALTER TABLE users 
MODIFY COLUMN age TINYINT UNSIGNED,
ALGORITHM=INPLACE;  -- 仅当类型兼容时

-- 4. 添加/删除主键
ALTER TABLE users 
DROP PRIMARY KEY,
ADD PRIMARY KEY (id, created_at),
ALGORITHM=INPLACE;

-- 5. 修改表选项
ALTER TABLE users 
ROW_FORMAT=DYNAMIC,
ALGORITHM=INPLACE;

-- 6. 重命名列(MySQL 8.0+)
ALTER TABLE users 
CHANGE COLUMN username account_name VARCHAR(50),
ALGORITHM=INPLACE;

-- 7. 修改自增值
ALTER TABLE users 
AUTO_INCREMENT = 1000000,
ALGORITHM=INPLACE;

篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc

需要全套面试笔记及答案
【点击此处即可/免费获取】

2.2 INPLACE锁级别控制

sql

复制

下载

复制代码
-- LOCK选项控制并发性
-- 1. LOCK=NONE (最高并发)
ALTER TABLE users 
ADD INDEX idx_phone (phone),
ALGORITHM=INPLACE,
LOCK=NONE;  -- 允许读写,不阻塞

-- 2. LOCK=SHARED (读并发)
ALTER TABLE users 
ADD INDEX idx_phone (phone),
ALGORITHM=INPLACE,
LOCK=SHARED;  -- 允许读,阻塞写

-- 3. LOCK=DEFAULT (自动选择)
ALTER TABLE users 
ADD INDEX idx_phone (phone),
ALGORITHM=INPLACE,
LOCK=DEFAULT;  -- MySQL自动选择最低锁级别

-- 4. LOCK=EXCLUSIVE (完全阻塞)
ALTER TABLE users 
ADD INDEX idx_phone (phone),
ALGORITHM=INPLACE,
LOCK=EXCLUSIVE;  -- 阻塞所有读写

-- 查看当前锁状态
SELECT * FROM performance_schema.metadata_locks 
WHERE OBJECT_SCHEMA = 'test_db' 
  AND OBJECT_NAME = 'users';

-- 监控锁等待
SELECT * FROM sys.innodb_lock_waits;

3. INPLACE优化策略

3.1 并行索引构建(MySQL 8.0+)

sql

复制

下载

复制代码
-- 启用并行索引构建
SET GLOBAL innodb_parallel_read_threads = 4;  -- 并行读取线程
SET GLOBAL innodb_ddl_threads = 4;            -- DDL并行线程
SET GLOBAL innodb_ddl_buffer_size = 134217728; -- 128MB缓冲区

-- 并行添加索引
ALTER TABLE large_table 
ADD INDEX idx_composite (col1, col2, col3),
ALGORITHM=INPLACE,
LOCK=NONE;

-- 查看并行执行
SELECT THREAD_ID, NAME, PROCESSLIST_INFO 
FROM performance_schema.threads 
WHERE NAME LIKE '%parallel%';
3.2 INPLACE空间优化

sql

复制

下载

复制代码
-- 1. 预估空间需求
SELECT 
    table_schema,
    table_name,
    round(((data_length + index_length) / 1024 / 1024), 2) as total_mb,
    round((data_length / 1024 / 1024), 2) as data_mb,
    round((index_length / 1024 / 1024), 2) as index_mb
FROM information_schema.TABLES 
WHERE table_name = 'users';

-- 2. 临时表空间监控
SELECT 
    FILE_NAME,
    TABLESPACE_NAME,
    INITIAL_SIZE/1024/1024 as initial_mb,
    AUTOEXTEND_SIZE/1024/1024 as autoextend_mb,
    MAXIMUM_SIZE/1024/1024 as max_mb
FROM information_schema.FILES 
WHERE FILE_TYPE = 'TEMPORARY';

-- 3. 在线日志监控
SHOW STATUS LIKE 'Innodb_online_alter_log%';
-- Innodb_online_alter_log_max_size
-- Innodb_online_alter_log_used

四、COPY算法详解

1. COPY算法原理

1.1 传统COPY算法流程

sql

复制

下载

复制代码
-- COPY算法执行流程(三阶段)

-- 阶段1: 创建临时表
--   CREATE TABLE tmp_table LIKE original_table;

-- 阶段2: 数据复制
--   INSERT INTO tmp_table SELECT * FROM original_table;
--   此阶段阻塞写操作

-- 阶段3: 切换表
--   RENAME TABLE original_table TO old_table,
--               tmp_table TO original_table;
--   DROP TABLE old_table;

-- 可视化流程
/*
原始表 users (10GB)
      ↓ COPY开始
临时表 tmp_users (空)
      ↓ 数据复制 (阻塞写)
临时表 tmp_users (10GB数据)
      ↓ 元数据锁切换 (短暂阻塞)
重命名: users → users_old, tmp_users → users
      ↓ 清理
DROP TABLE users_old
*/
1.2 COPY算法空间需求

sql

复制

下载

复制代码
-- COPY算法需要双倍空间
-- 原始表大小 + 临时表大小 ≈ 2 × 原始表大小

-- 计算表空间需求
SELECT 
    table_name,
    round(((data_length + index_length) / 1024 / 1024 / 1024), 2) as table_size_gb,
    round(((data_length + index_length) * 2 / 1024 / 1024 / 1024), 2) as required_space_gb
FROM information_schema.TABLES 
WHERE table_schema = 'your_db' 
  AND table_name = 'your_table';

-- 监控磁盘空间
SELECT 
    table_schema,
    sum(round(((data_length + index_length) / 1024 / 1024 / 1024), 2)) as total_gb
FROM information_schema.TABLES 
GROUP BY table_schema;

2. COPY算法使用场景

2.1 必须使用COPY的场景

sql

复制

下载

复制代码
-- 1. 更改列顺序
ALTER TABLE users 
MODIFY COLUMN email VARCHAR(100) AFTER username,
ALGORITHM=COPY;  -- 必须使用COPY

-- 2. 修改存储引擎
ALTER TABLE users 
ENGINE=MyISAM,
ALGORITHM=COPY;  -- 跨引擎转换

-- 3. 修改字符集(表级)
ALTER TABLE users 
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
ALGORITHM=COPY;

-- 4. 删除主键(无新主键)
ALTER TABLE users 
DROP PRIMARY KEY,
ALGORITHM=COPY;  -- 如果没有新主键

-- 5. 添加自增列
ALTER TABLE users 
ADD COLUMN seq_id INT AUTO_INCREMENT UNIQUE,
ALGORITHM=COPY;  -- 需要重新组织数据
2.2 COPY算法性能优化

sql

复制

下载

复制代码
-- 1. 分批执行大表DDL
-- 方法:创建新表,分批导入数据
CREATE TABLE users_new LIKE users;
-- 修改新表结构
ALTER TABLE users_new 
ADD COLUMN new_col INT,
ALGORITHM=COPY;  -- 空表很快

-- 分批导入数据(避免长事务)
INSERT INTO users_new 
SELECT *, 0 as new_col FROM users WHERE id BETWEEN 1 AND 100000;

INSERT INTO users_new 
SELECT *, 0 as new_col FROM users WHERE id BETWEEN 100001 AND 200000;
-- ... 继续分批

-- 最终切换
RENAME TABLE users TO users_old, users_new TO users;

-- 2. 使用pt-online-schema-change
# 外部工具,触发器实现
pt-online-schema-change \
  --alter="ADD COLUMN new_col INT" \
  D=test_db,t=users \
  --execute

3. COPY与INPLACE对比场景

3.1 相同操作的不同算法

sql

复制

下载

复制代码
-- 场景:修改列类型
CREATE TABLE test (
    id INT PRIMARY KEY,
    price DECIMAL(10,2)
);

-- 情况1:兼容修改 → INPLACE
ALTER TABLE test 
MODIFY COLUMN price DECIMAL(10,3),
ALGORITHM=INPLACE;  -- 仅修改精度,允许INPLACE

-- 情况2:不兼容修改 → COPY
ALTER TABLE test 
MODIFY COLUMN price VARCHAR(20),
ALGORITHM=COPY;  -- 类型完全改变,需要COPY

-- 查看算法选择
ALTER TABLE test 
MODIFY COLUMN price DECIMAL(12,2),
ALGORITHM=DEFAULT;  -- MySQL自动选择

-- 验证算法选择
SHOW CREATE TABLE test\G
-- 查看information_schema
SELECT * FROM information_schema.INNODB_TABLES 
WHERE NAME LIKE '%test%';

五、三种算法实战对比

1. 操作兼容性矩阵

操作类型 INSTANT INPLACE COPY 备注
添加列 ✅ 8.0+ ✅ 5.6+ ✅ 所有 INSTANT最快
删除列 ✅ 8.0.29+ ✅ 所有
重命名列 ✅ 8.0.28+ ✅ 8.0+ ✅ 所有
修改列类型 ⚠️ 部分 ✅ 所有
添加索引 ✅ 5.6+ ✅ 所有
删除索引 ✅ 5.6+ ✅ 所有
重建表 ✅ 5.6+ ✅ 所有 OPTIMIZE TABLE
修改字符集 ✅ 所有
分区操作 ⚠️ 部分 ⚠️ 部分 ✅ 所有

2. 性能基准测试对比

sql

复制

下载

复制代码
-- 创建测试环境
CREATE DATABASE IF NOT EXISTS ddl_benchmark;
USE ddl_benchmark;

-- 创建大表(1000万行)
CREATE TABLE large_table (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    uuid CHAR(36) NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    data1 VARCHAR(255),
    data2 VARCHAR(255),
    data3 VARCHAR(255),
    INDEX idx_uuid (uuid),
    INDEX idx_created (created_at)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

-- 插入测试数据(使用存储过程简化)
DELIMITER //
CREATE PROCEDURE populate_data(IN num_rows INT)
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < num_rows DO
        INSERT INTO large_table (uuid, data1, data2, data3)
        VALUES (UUID(), MD5(RAND()), MD5(RAND()), MD5(RAND()));
        SET i = i + 1;
        IF i % 10000 = 0 THEN
            COMMIT;
        END IF;
    END WHILE;
END//
DELIMITER ;

-- 调用存储过程插入1000万数据
-- CALL populate_data(10000000); -- 实际执行需要时间

-- 测试脚本
SET @iterations = 5;

-- 1. INSTANT添加列测试
DROP PROCEDURE IF EXISTS test_instant;
DELIMITER //
CREATE PROCEDURE test_instant()
BEGIN
    DECLARE i INT DEFAULT 0;
    DECLARE total_time DECIMAL(10,3) DEFAULT 0;
    
    WHILE i < @iterations DO
        SET @start = NOW(6);
        
        ALTER TABLE large_table 
        ADD COLUMN test_instant_col INT DEFAULT 0,
        ALGORITHM=INSTANT;
        
        SET @end = NOW(6);
        SET total_time = total_time + 
            TIMESTAMPDIFF(MICROSECOND, @start, @end)/1000000;
        
        -- 清理
        ALTER TABLE large_table 
        DROP COLUMN test_instant_col,
        ALGORITHM=COPY;  -- DROP需要COPY
        
        SET i = i + 1;
    END WHILE;
    
    SELECT 'INSTANT' as algorithm, 
           total_time/@iterations as avg_seconds,
           total_time as total_seconds;
END//
DELIMITER ;

-- 2. INPLACE添加索引测试
DROP PROCEDURE IF EXISTS test_inplace;
DELIMITER //
CREATE PROCEDURE test_inplace()
BEGIN
    DECLARE i INT DEFAULT 0;
    DECLARE total_time DECIMAL(10,3) DEFAULT 0;
    
    WHILE i < @iterations DO
        SET @start = NOW(6);
        
        ALTER TABLE large_table 
        ADD INDEX idx_test_inplace (data1(100)),
        ALGORITHM=INPLACE,
        LOCK=NONE;
        
        SET @end = NOW(6);
        SET total_time = total_time + 
            TIMESTAMPDIFF(MICROSECOND, @start, @end)/1000000;
        
        -- 清理
        ALTER TABLE large_table 
        DROP INDEX idx_test_inplace,
        ALGORITHM=INPLACE,
        LOCK=NONE;
        
        SET i = i + 1;
    END WHILE;
    
    SELECT 'INPLACE' as algorithm, 
           total_time/@iterations as avg_seconds,
           total_time as total_seconds;
END//
DELIMITER ;

-- 3. COPY修改列类型测试
DROP PROCEDURE IF EXISTS test_copy;
DELIMITER //
CREATE PROCEDURE test_copy()
BEGIN
    DECLARE i INT DEFAULT 0;
    DECLARE total_time DECIMAL(10,3) DEFAULT 0;
    
    -- 先添加测试列
    ALTER TABLE large_table 
    ADD COLUMN test_copy_col VARCHAR(100) DEFAULT 'test',
    ALGORITHM=INSTANT;
    
    WHILE i < @iterations DO
        SET @start = NOW(6);
        
        ALTER TABLE large_table 
        MODIFY COLUMN test_copy_col VARCHAR(200),
        ALGORITHM=COPY;
        
        SET @end = NOW(6);
        SET total_time = total_time + 
            TIMESTAMPDIFF(MICROSECOND, @start, @end)/1000000;
        
        SET i = i + 1;
    END WHILE;
    
    -- 清理
    ALTER TABLE large_table 
    DROP COLUMN test_copy_col,
    ALGORITHM=COPY;
    
    SELECT 'COPY' as algorithm, 
           total_time/@iterations as avg_seconds,
           total_time as total_seconds;
END//
DELIMITER ;

-- 执行测试
CALL test_instant();
CALL test_inplace();
CALL test_copy();

3. 生产环境选择策略

sql

复制

下载

复制代码
-- 决策树:选择DDL算法的逻辑
/*
                         开始DDL操作
                               ↓
                    是否支持INSTANT算法?
                   /                        \
                是                          否
                 ↓                           ↓
        使用INSTANT执行          是否支持INPLACE算法?
                                   /                  \
                                是                    否
                                 ↓                     ↓
                        使用INPLACE执行         使用COPY算法
                                ↓
                     根据业务负载选择LOCK级别
                     (NONE < SHARED < EXCLUSIVE)
*/

-- 自动化选择函数
DELIMITER //
CREATE FUNCTION recommend_algorithm(
    p_operation VARCHAR(50),
    p_mysql_version VARCHAR(10),
    p_table_size_mb DECIMAL(10,2),
    p_peak_hour BOOLEAN
) RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
    DECLARE v_algorithm VARCHAR(20);
    DECLARE v_major_version INT;
    
    SET v_major_version = SUBSTRING_INDEX(p_mysql_version, '.', 1);
    
    -- INSTANT算法检查
    IF v_major_version >= 8 THEN
        IF p_operation IN ('ADD_COLUMN', 'DROP_COLUMN', 'RENAME_COLUMN') THEN
            IF p_table_size_mb > 1024 AND p_peak_hour = TRUE THEN
                SET v_algorithm = 'INSTANT';
            ELSE
                SET v_algorithm = 'INPLACE';
            END IF;
        ELSE
            SET v_algorithm = 'INPLACE';
        END IF;
    ELSE
        -- MySQL 5.6/5.7
        IF p_operation IN ('ADD_INDEX', 'DROP_INDEX') THEN
            SET v_algorithm = 'INPLACE';
        ELSE
            SET v_algorithm = 'COPY';
        END IF;
    END IF;
    
    RETURN v_algorithm;
END//
DELIMITER ;

-- 使用示例
SELECT 
    recommend_algorithm(
        'ADD_COLUMN',
        @@version,
        (SELECT round(((data_length + index_length)/1024/1024), 2)
         FROM information_schema.TABLES 
         WHERE table_schema = 'test' AND table_name = 'users'),
        HOUR(NOW()) BETWEEN 9 AND 18
    ) as recommended_algorithm;

六、监控与故障处理

1. DDL执行监控

1.1 实时监控DDL进度

sql

复制

下载

复制代码
-- MySQL 8.0+ 进度监控
SELECT 
    pps.THREAD_ID,
    t.PROCESSLIST_ID as conn_id,
    t.PROCESSLIST_USER as user,
    t.PROCESSLIST_HOST as host,
    t.PROCESSLIST_DB as db,
    t.PROCESSLIST_COMMAND as command,
    t.PROCESSLIST_INFO as query,
    es.STAGE_NAME,
    es.WORK_COMPLETED,
    es.WORK_ESTIMATED,
    CASE 
        WHEN es.WORK_ESTIMATED > 0 THEN 
            ROUND((es.WORK_COMPLETED / es.WORK_ESTIMATED) * 100, 2)
        ELSE 0
    END as progress_pct,
    ROUND(es.TIMER_WAIT / 1000000000000, 2) as elapsed_seconds
FROM performance_schema.threads t
LEFT JOIN performance_schema.events_stages_current es 
    ON t.THREAD_ID = es.THREAD_ID
LEFT JOIN performance_schema.events_statements_current psc 
    ON t.THREAD_ID = psc.THREAD_ID
WHERE t.PROCESSLIST_COMMAND = 'Query'
  AND t.PROCESSLIST_INFO LIKE 'ALTER TABLE%'
  AND es.STAGE_NAME LIKE '%alter%';
1.2 历史DDL监控

sql

复制

下载

复制代码
-- 创建DDL监控表
CREATE TABLE ddl_monitor (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    start_time DATETIME(6) NOT NULL,
    end_time DATETIME(6),
    schema_name VARCHAR(64) NOT NULL,
    table_name VARCHAR(64) NOT NULL,
    ddl_statement TEXT NOT NULL,
    algorithm VARCHAR(20),
    lock_type VARCHAR(20),
    rows_affected BIGINT,
    duration_ms BIGINT,
    status ENUM('RUNNING', 'COMPLETED', 'FAILED') DEFAULT 'RUNNING',
    error_message TEXT,
    created_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),
    INDEX idx_table (schema_name, table_name),
    INDEX idx_time (start_time),
    INDEX idx_status (status)
) ENGINE=InnoDB;

-- 创建监控触发器
DELIMITER //
CREATE TRIGGER ddl_monitor_start 
AFTER UPDATE ON information_schema.INNODB_TABLES
FOR EACH ROW
BEGIN
    -- 通过解析processlist检测DDL开始
    -- 实际实现需要更复杂的逻辑
END//
DELIMITER ;

2. 常见故障处理

2.1 空间不足处理

sql

复制

下载

复制代码
-- 1. 检查空间使用
SELECT 
    table_schema,
    table_name,
    round(((data_length + index_length) / 1024 / 1024), 2) as size_mb,
    round((data_free / 1024 / 1024), 2) as free_mb
FROM information_schema.TABLES 
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema')
ORDER BY size_mb DESC
LIMIT 10;

-- 2. 清理旧数据
-- 方案1:归档历史数据
CREATE TABLE users_archive LIKE users;
INSERT INTO users_archive 
SELECT * FROM users WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);
DELETE FROM users WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);

-- 方案2:使用分区表
ALTER TABLE users 
PARTITION BY RANGE (YEAR(created_at)) (
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022),
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

-- 删除旧分区
ALTER TABLE users DROP PARTITION p2020;
2.2 长事务阻塞DDL

sql

复制

下载

复制代码
-- 1. 查找阻塞DDL的长事务
SELECT 
    r.trx_id as blocking_trx_id,
    r.trx_mysql_thread_id as blocking_thread,
    r.trx_started as blocking_started,
    TIMESTAMPDIFF(SECOND, r.trx_started, NOW()) as blocking_duration_sec,
    r.trx_query as blocking_query,
    b.requesting_trx_id as waiting_trx_id,
    b.requesting_lock_id as waiting_lock,
    t.PROCESSLIST_INFO as waiting_query
FROM information_schema.INNODB_TRX r
JOIN information_schema.INNODB_LOCK_WAITS b 
    ON r.trx_id = b.blocking_trx_id
JOIN information_schema.INNODB_TRX w 
    ON b.requesting_trx_id = w.trx_id
LEFT JOIN performance_schema.threads t 
    ON w.trx_mysql_thread_id = t.PROCESSLIST_ID
WHERE r.trx_state = 'RUNNING'
ORDER BY blocking_duration_sec DESC;

-- 2. 安全终止长事务
-- 首先尝试回滚
KILL QUERY <thread_id>;

-- 如果不行,强制终止(谨慎使用)
KILL <thread_id>;

-- 3. 设置事务超时
SET SESSION innodb_lock_wait_timeout = 30;  -- 30秒超时
SET SESSION lock_wait_timeout = 30;

七、最佳实践总结

1. 版本升级建议

sql

复制

下载

复制代码
-- 升级到MySQL 8.0+以获得INSTANT支持
-- 升级前检查表兼容性

-- 1. 检查表格式
SELECT 
    table_name,
    engine,
    row_format,
    table_rows,
    round(((data_length + index_length) / 1024 / 1024), 2) as size_mb,
    CASE 
        WHEN row_format IN ('COMPACT', 'REDUNDANT') THEN '可能需要转换'
        WHEN row_format IN ('DYNAMIC', 'COMPRESSED') THEN '兼容INSTANT'
        ELSE '未知'
    END as instant_compatibility
FROM information_schema.TABLES 
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema')
  AND engine = 'InnoDB'
ORDER BY size_mb DESC;

-- 2. 转换表格式
ALTER TABLE table_name ROW_FORMAT=DYNAMIC;

-- 3. 验证INSTANT支持
ALTER TABLE table_name 
ADD COLUMN test_instant INT DEFAULT 0,
ALGORITHM=INSTANT;
-- 如果成功,说明支持INSTANT
ALTER TABLE table_name DROP COLUMN test_instant;

2. 生产环境DDL策略

sql

复制

下载

复制代码
-- DDL执行检查清单
/*
✅ 前置检查:
  1. 备份数据(至少要有逻辑备份)
  2. 检查磁盘空间(至少2倍表空间)
  3. 选择业务低峰期
  4. 设置会话参数
  5. 通知相关方

✅ 执行策略:
  1. 优先尝试INSTANT
  2. 其次INPLACE (LOCK=NONE)
  3. 最后考虑COPY
  4. 大表考虑分批执行

✅ 监控要点:
  1. 进度监控
  2. 空间监控
  3. 性能影响监控
  4. 错误日志监控

✅ 回滚方案:
  1. 准备好回滚脚本
  2. 测试回滚流程
  3. 保留足够备份
*/

篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc

需要全套面试笔记及答案
【点击此处即可/免费获取】

3. 自动化DDL管理脚本

bash

复制

下载

复制代码
#!/bin/bash
# ddl_manager.sh - 自动化DDL管理

# 配置
MYSQL_HOST="localhost"
MYSQL_PORT="3306"
MYSQL_USER="admin"
MYSQL_PASS="password"
BACKUP_DIR="/backup/ddl"
LOG_DIR="/var/log/ddl"

# 执行DDL
execute_ddl() {
    local DB="$1"
    local TABLE="$2"
    local DDL_SQL="$3"
    
    # 创建备份
    local TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    local BACKUP_FILE="${BACKUP_DIR}/${DB}_${TABLE}_${TIMESTAMP}.sql"
    
    echo "[$(date)] 开始执行DDL: ${DB}.${TABLE}" | tee -a "${LOG_DIR}/ddl.log"
    
    # 逻辑备份
    mysqldump -h${MYSQL_HOST} -P${MYSQL_PORT} -u${MYSQL_USER} -p${MYSQL_PASS} \
        --single-transaction --routines --triggers \
        ${DB} ${TABLE} > "${BACKUP_FILE}"
    
    if [ $? -ne 0 ]; then
        echo "[$(date)] 备份失败,终止DDL" | tee -a "${LOG_DIR}/ddl.log"
        return 1
    fi
    
    # 执行DDL(带超时)
    timeout 3600 mysql -h${MYSQL_HOST} -P${MYSQL_PORT} -u${MYSQL_USER} -p${MYSQL_PASS} ${DB} <<EOF
SET SESSION lock_wait_timeout = 30;
SET SESSION innodb_lock_wait_timeout = 30;
${DDL_SQL}
EOF
    
    local DDL_STATUS=$?
    
    if [ $DDL_STATUS -eq 0 ]; then
        echo "[$(date)] DDL执行成功" | tee -a "${LOG_DIR}/ddl.log"
        # 可选:清理旧备份
        find "${BACKUP_DIR}" -name "${DB}_${TABLE}_*.sql" -mtime +7 -delete
    elif [ $DDL_STATUS -eq 124 ]; then
        echo "[$(date)] DDL执行超时" | tee -a "${LOG_DIR}/ddl.log"
        # 回滚?
    else
        echo "[$(date)] DDL执行失败" | tee -a "${LOG_DIR}/ddl.log"
        # 恢复备份?
    fi
    
    return $DDL_STATUS
}

# 使用示例
# execute_ddl "myapp" "users" "ALTER TABLE users ADD COLUMN middle_name VARCHAR(50), ALGORITHM=INSTANT"

八、未来发展趋势

1. MySQL 8.1+新特性

sql

复制

下载

复制代码
-- 预期改进方向

-- 1. 更多INSTANT操作支持
-- 预计支持:修改列类型、添加外键等

-- 2. 并行DDL增强
-- 更细粒度的并行控制

-- 3. 在线分区管理
-- 支持更多的在线分区操作

-- 4. DDL原子性增强
-- 更完善的原子DDL支持

2. 云原生DDL优化

sql

复制

下载

复制代码
-- 云数据库的DDL优化
-- 1. 异步DDL执行
-- 2. 分布式DDL协调
-- 3. 智能算法选择
-- 4. 自动回滚机制

-- 例如AWS RDS/Aurora的优化
ALTER TABLE users 
ADD COLUMN new_column INT,
ALGORITHM=INSTANT,
WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS = 'auto';

核心建议

  • MySQL 8.0+用户优先使用INSTANT算法

  • 大表操作务必测试和监控

  • 始终准备好回滚方案

  • 结合业务特点选择最佳算法

相关推荐
じ☆冷颜〃9 分钟前
黎曼几何驱动的算法与系统设计:理论、实践与跨领域应用
笔记·python·深度学习·网络协议·算法·机器学习
数据大魔方22 分钟前
【期货量化实战】日内动量策略:顺势而为的短线交易法(Python源码)
开发语言·数据库·python·mysql·算法·github·程序员创富
POLITE323 分钟前
Leetcode 23. 合并 K 个升序链表 (Day 12)
算法·leetcode·链表
楚来客41 分钟前
AI基础概念之八:Transformer算法通俗解析
人工智能·算法·transformer
Echo_NGC22371 小时前
【神经视频编解码NVC】传统神经视频编解码完全指南:从零读懂 AI 视频压缩的基石
人工智能·深度学习·算法·机器学习·视频编解码
会员果汁1 小时前
leetcode-动态规划-买卖股票
算法·leetcode·动态规划
橘颂TA2 小时前
【剑斩OFFER】算法的暴力美学——二进制求和
算法·leetcode·哈希算法·散列表·结构与算法
地平线开发者3 小时前
征程 6 | cgroup sample
算法·自动驾驶
姓蔡小朋友4 小时前
算法-滑动窗口
算法