产品概述
应用场景
产品架构
实例类型
兼容性说明
使用规范建议
ALTER TABLE)需要获取目标表的 MDL 排他锁(MDL-X)。当目标表上存在未提交的长事务或大查询时,这些会话持有该表的 MDL 共享读锁,DDL 将进入等待状态。SELECT、INSERT、UPDATE)都将被阻塞——它们既无法获取 MDL 共享锁(因为等待队列中有优先级更高的排他锁请求),也无法绕过排他锁请求直接执行。维度 | 抢占式 DDL | 非阻塞 DDL |
解决的问题 | DDL 因长事务阻塞而执行失败 | DDL 等待期间阻塞所有新事务 |
处理方式 | 超时后终止阻塞 DDL 的会话 | 超时后 DDL 主动退让,放行新事务 |
对已有会话的影响 | 持锁会话会被强制终止 | 不影响任何已有会话 |
DDL 执行结果 | DDL 一定成功 | DDL 可能因重试次数耗尽而失败 |
适用场景 | 可接受中断长事务,要求 DDL 必须成功 | 不可中断业务会话,要求业务零感知 |
参数 | 级别 | 说明 | 取值范围 | 默认值 |
tdsql_ddl_block_mode | Session | 非阻塞 DDL 功能开关,设置为 nonblock 时启用非阻塞 DDL 逻辑。 | preemptive nonblock default | preemptive |
tdsql_ddl_recovery_block_mode | Global | 控制恢复线程的非阻塞 DDL 行为,设置为 nonblock 时生效;仅 GLOBAL 级别设置生效,Session 级别设置无效 | preemptive nonblock default | preemptive |
tdsql_ddl_nonblock_lock_wait_timeout | Session | 单次尝试获取 MDL-X 锁的超时时间。超过该时间未获取到锁,DDL 将主动放弃本次请求,允许新事务通过。单位:秒 | 1 ~ 102410241024 | 1 |
tdsql_ddl_nonblock_retry_interval | Session | 两次锁获取尝试之间的等待间隔。单位:秒 | 0 ~ 60 | 4 |
tdsql_ddl_nonblock_retry_times | Session | 获取 MDL-X 锁的最大重试次数。超过该次数后 DDL 将执行失败。 | 0 ~ ULONG_MAX | 10 |
总时长 ≈ tdsql_ddl_nonblock_retry_times × (tdsql_ddl_nonblock_lock_wait_timeout + tdsql_ddl_nonblock_retry_interval)
SET tdsql_ddl_block_mode = 'nonblock';
SET tdsql_ddl_nonblock_lock_wait_timeout = 2;SET tdsql_ddl_nonblock_retry_interval = 5;SET tdsql_ddl_nonblock_retry_times = 20;
SET GLOBAL tdsql_ddl_recovery_block_mode = 'nonblock';
ALTER TABLE orders ADD INDEX idx_status (status);
CREATE TABLE sbtest1 (id INT PRIMARY KEY,k INT NOT NULL DEFAULT 0,c CHAR(120) NOT NULL DEFAULT '',pad CHAR(60) NOT NULL DEFAULT '');-- 插入 100 万行测试数据(可通过 SysBench 等工具生成)
sysbench oltp_read_write \\--mysql-host="连接地址" \\--mysql-port=3306 \\--mysql-user="用户名" \\--mysql-password="密码" \\--mysql-db="test" \\--tables=1 \\--table-size=1000000 \\--threads=8 \\--time=600 \\--report-interval=1 \\run
BEGIN;SELECT * FROM sbtest1 LIMIT 1;-- 不提交,持有 sbtest1 的 MDL 共享读锁
ALTER TABLE sbtest1 ADD COLUMN d INT;-- DDL 进入 MDL 锁等待队列-- 此时所有新事务也被阻塞 → 业务 TPS 跌零
SET tdsql_nonblock_ddl_mode = ON;SET tdsql_nonblock_ddl_lock_wait_timeout = 1;SET tdsql_nonblock_ddl_retry_interval = 5;SET tdsql_nonblock_ddl_retry_times = 50;ALTER TABLE sbtest1 ADD COLUMN d INT;-- DDL 尝试获取锁 → 1 秒后放弃 → 放行新事务 → 等待 5 秒 → 再次尝试...-- 当会话 1 的事务结束后,DDL 在下一次重试时获取锁成功-- Query OK, 0 rows affected (23.15 sec)
场景 | TPS 表现 | 业务影响 |
关闭非阻塞 DDL | TPS 持续跌零,直到锁释放 | 严重,业务完全中断 |
开启非阻塞 DDL | TPS 周期性短暂下降,不跌零 | 较小,业务保持可用 |
-- 开启非阻塞 DDL,避免影响在线业务SET tdsql_ddl_block_mode = 'nonblock';SET tdsql_ddl_nonblock_lock_wait_timeout = 1;SET tdsql_ddl_nonblock_retry_interval = 3;SET tdsql_ddl_nonblock_retry_times = 100;ALTER TABLE orders ADD INDEX idx_create_time (create_time);
-- 第一次尝试:非阻塞模式,不影响业务SET tdsql_ddl_block_mode = 'nonblock';SET tdsql_ddl_nonblock_retry_times = 10;ALTER TABLE orders ADD COLUMN remark VARCHAR(255);-- 如果重试耗尽仍失败...-- 第二次尝试:抢占模式,强制完成SET tdsql_ddl_block_mode = 'preemptive';SET tdsql_ddl_preempt_after_wait_seconds = 5;ALTER TABLE orders ADD COLUMN remark VARCHAR(255);
文档反馈