MySQL 数据库高级与网络管理操作命令大全

说明:高级与网络管理涵盖存储程序(存储过程、函数、触发器、事件)、JSON数据处理、窗口函数、CTE、分区管理、复制架构、集群部署(InnoDB Cluster / Group Replication)、MySQL Router、SSL/TLS加密连接以及连接管理等运维级网络功能。本指南是 MySQL 系列文章中的最后一篇,提供完整的语法、命令和实用示例。

一、存储程序管理(Stored Programs)

存储程序是预先编译并存储在数据库中的 SQL 语句集合,包括存储过程、存储函数、触发器和事件。这些程序在服务器端执行,可以显著减少应用程序与数据库之间的数据传输,提高性能和代码重用性。

1.1 定界符(DELIMITER)

在创建存储程序时,由于过程体内部可能包含分号 ;,需要临时更改 MySQL 语句的定界符,以防止客户端提前结束命令。

sql 复制代码
-- 将定界符临时改为 //
DELIMITER //

-- 执行存储程序创建语句(内部可以使用 ;)

-- 恢复定界符为 ;
DELIMITER ;

DELIMITER 是 mysql 客户端的命令,而非服务端 SQL 语言的一部分。⚠️ 注意:如果通过 API 执行或在 Workbench 中运行,通常不需要更改定界符。

1.2 存储过程(Stored Procedure)

存储过程是一组为了完成特定功能的 SQL 语句集合,被编译后存储在数据库中,可被重复调用。

创建存储过程(CREATE PROCEDURE)

语法

sql 复制代码
CREATE PROCEDURE 过程名 ([参数模式] 参数名 数据类型 [, ...])
    [特性...]
BEGIN
    过程体
END

参数模式说明:

  • IN:输入参数(默认),调用时必须传入值
  • OUT:输出参数,用于将值返回给调用者
  • INOUT:既是输入又是输出

示例

sql 复制代码
DELIMITER //

-- 无参数存储过程
CREATE PROCEDURE GetAllUsers()
BEGIN
    SELECT * FROM users;
END //

-- 带 IN 参数的存储过程
CREATE PROCEDURE GetUserById(IN userId INT)
BEGIN
    SELECT * FROM users WHERE id = userId;
END //

-- 带 OUT 参数的存储过程
CREATE PROCEDURE GetUserCount(OUT total INT)
BEGIN
    SELECT COUNT(*) INTO total FROM users;
END //

-- 带 INOUT 参数的存储过程
CREATE PROCEDURE DoubleValue(INOUT value INT)
BEGIN
    SET value = value * 2;
END //

DELIMITER ;

调用存储过程(CALL)

sql 复制代码
CALL GetUserById(100);
CALL GetUserCount(@count);
SELECT @count;          -- 获取输出参数值

SET @val = 10;
CALL DoubleValue(@val);
SELECT @val;            -- 输出 20

查看存储过程

sql 复制代码
-- 查看所有存储过程
SHOW PROCEDURE STATUS;
SHOW PROCEDURE STATUS WHERE Db = 'database_name';

-- 查看存储过程的创建定义
SHOW CREATE PROCEDURE 过程名;

修改存储过程(ALTER PROCEDURE)

语法

sql 复制代码
ALTER PROCEDURE 过程名 [特性...];

示例

sql 复制代码
ALTER PROCEDURE GetUserById COMMENT '根据ID查询用户';

⚠️ 注意ALTER PROCEDURE 不能修改过程体,只能修改特性(如 COMMENT、SQL SECURITY 等)。要修改过程体,需要先删除再重建。

删除存储过程(DROP PROCEDURE)

sql 复制代码
DROP PROCEDURE IF EXISTS GetUserById;

存储过程中的控制流语句

sql 复制代码
DELIMITER //
CREATE PROCEDURE UpdateBalance(IN customerId INT, IN amount DECIMAL(10,2))
BEGIN
    DECLARE currentBalance DECIMAL(10,2);
    
    SELECT balance INTO currentBalance FROM customers WHERE id = customerId;
    
    IF currentBalance + amount >= 0 THEN
        UPDATE customers SET balance = currentBalance + amount WHERE id = customerId;
    ELSE
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '余额不足';
    END IF;
END //
DELIMITER ;

1.3 存储函数(Stored Function)

存储函数与存储过程类似,但必须返回一个值,且可以在表达式中直接调用。

创建存储函数(CREATE FUNCTION)

语法

sql 复制代码
CREATE FUNCTION 函数名 ([参数名 数据类型 [, ...]])
    RETURNS 返回类型
    [特性...]
BEGIN
    函数体
    RETURN 返回值;
END

示例

sql 复制代码
DELIMITER //

-- 标量函数,返回用户年龄
CREATE FUNCTION GetUserAge(userId INT)
    RETURNS INT
    DETERMINISTIC
    READS SQL DATA
BEGIN
    DECLARE ageVal INT;
    SELECT age INTO ageVal FROM users WHERE id = userId;
    RETURN ageVal;
END //

DELIMITER ;

-- 在 SQL 表达式中使用函数
SELECT name, GetUserAge(id) AS user_age FROM users;

查看和删除存储函数

sql 复制代码
SHOW FUNCTION STATUS;
SHOW CREATE FUNCTION GetUserAge;
DROP FUNCTION IF EXISTS GetUserAge;

1.4 触发器(Trigger)

触发器是一种特殊的存储程序,在特定表上的 INSERT、UPDATE 或 DELETE 事件发生时自动执行,无需显式调用。执行时机可以为 BEFOREAFTER,作用范围可以是 FOR EACH ROW(MySQL 仅支持行级触发器)。

创建触发器(CREATE TRIGGER)

语法

sql 复制代码
CREATE TRIGGER 触发器名
    {BEFORE | AFTER} {INSERT | UPDATE | DELETE}
    ON 表名 FOR EACH ROW
BEGIN
    触发器体
END

示例

sql 复制代码
DELIMITER //

-- BEFORE INSERT:在插入前自动设置创建时间
CREATE TRIGGER before_user_insert
    BEFORE INSERT ON users FOR EACH ROW
BEGIN
    SET NEW.created_at = NOW();
    SET NEW.updated_at = NOW();
END //

-- AFTER UPDATE:记录更新时间后的日志
CREATE TRIGGER after_user_update
    AFTER UPDATE ON users FOR EACH ROW
BEGIN
    INSERT INTO user_logs (user_id, old_name, new_name, old_age, new_age, changed_at)
    VALUES (OLD.id, OLD.name, NEW.name, OLD.age, NEW.age, NOW());
END //

-- BEFORE DELETE:在删除前备份被删除的行
CREATE TRIGGER before_user_delete
    BEFORE DELETE ON users FOR EACH ROW
BEGIN
    INSERT INTO users_archive (id, name, age, deleted_at)
    VALUES (OLD.id, OLD.name, OLD.age, NOW());
END //

DELIMITER ;

在触发器体中可以引用被操作行的新旧数据:

  • NEW.列名:对于 INSERT 和 UPDATE 操作,表示新值
  • OLD.列名:对于 UPDATE 和 DELETE 操作,表示旧值

查看触发器

sql 复制代码
-- 查看所有触发器
SHOW TRIGGERS;

-- 查看指定表的触发器
SHOW TRIGGERS WHERE `Table` = 'users';

-- 查看触发器创建语句
SHOW CREATE TRIGGER before_user_insert;

删除触发器(DROP TRIGGER)

sql 复制代码
DROP TRIGGER IF EXISTS before_user_insert;

1.5 事件调度器(Event Scheduler)

事件调度器是基于时间的任务调度器,类似于 Linux 的 crontab,用于定期执行 SQL 语句。

查看和启用事件调度器

sql 复制代码
-- 查看事件调度器是否开启
SHOW VARIABLES LIKE 'event_scheduler';

-- 启用事件调度器(临时,重启后失效)
SET GLOBAL event_scheduler = ON;

-- 永久启用:在 my.cnf 中添加 event_scheduler=ON

创建事件(CREATE EVENT)

语法

sql 复制代码
CREATE EVENT [IF NOT EXISTS] 事件名
    ON SCHEDULE 调度规则
    [ON COMPLETION [NOT] PRESERVE]
    [ENABLE | DISABLE]
    DO 执行的SQL语句;

调度规则

  • AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR:单次执行
  • EVERY 1 DAY:每天重复
  • EVERY 1 MONTH STARTS '2026-01-01 00:00:00':从指定时间开始
  • EVERY 1 DAY ENDS '2027-01-01 00:00:00':到指定时间结束

示例

sql 复制代码
-- 创建一次性事件(1小时后清理临时表)
CREATE EVENT cleanup_temp
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
    DO
        TRUNCATE TABLE temp_logs;

-- 每天凌晨 2 点统计日志
CREATE EVENT daily_log_stats
    ON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 02:00:00'
    DO
        INSERT INTO log_stats (stat_date, count)
        SELECT CURDATE(), COUNT(*) FROM logs WHERE DATE(created_at) = CURDATE();

-- 每小时归档旧订单
CREATE EVENT archive_old_orders
    ON SCHEDULE EVERY 1 HOUR
    ON COMPLETION PRESERVE        -- 事件执行后保持定义(不删除)
    ENABLE
    DO
        INSERT INTO orders_archive SELECT * FROM orders WHERE created_at < NOW() - INTERVAL 90 DAY;
        DELETE FROM orders WHERE created_at < NOW() - INTERVAL 90 DAY;

修改事件(ALTER EVENT)

sql 复制代码
-- 修改事件的调度时间
ALTER EVENT daily_log_stats ON SCHEDULE EVERY 1 DAY STARTS '2026-02-01 02:00:00';

-- 禁用事件
ALTER EVENT daily_log_stats DISABLE;

-- 启用事件
ALTER EVENT daily_log_stats ENABLE;

-- 修改事件体
ALTER EVENT daily_log_stats DO INSERT INTO log_day_stats SELECT COUNT(*) FROM logs;

查看和删除事件

sql 复制代码
-- 查看所有事件
SHOW EVENTS;

-- 查看创建语句
SHOW CREATE EVENT daily_log_stats;

-- 删除事件
DROP EVENT IF EXISTS daily_log_stats;

二、JSON 数据类型与函数(MySQL 5.7+ / 8.0+)

MySQL 从 5.7 版本开始原生支持 JSON 数据类型,允许存储和高效操作 JSON 文档。

2.1 创建 JSON 列与插入数据

sql 复制代码
-- 创建包含 JSON 列的表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    profile JSON
);

-- 插入 JSON 数据
INSERT INTO users (name, profile) VALUES
    ('张三', '{"age": 30, "city": "北京", "tags": ["developer", "dba"]}'),
    ('李四', '{"age": 25, "city": "上海", "tags": ["manager"]}');

2.2 JSON 查询函数

JSON_EXTRACT / -> / ->>

sql 复制代码
-- 使用 JSON_EXTRACT 提取值(带引号)
SELECT JSON_EXTRACT(profile, '$.city') FROM users;

-- 使用 -> 运算符(等价于 JSON_EXTRACT)
SELECT profile->'$.city' FROM users;   -- 返回 "北京"

-- 使用 ->> 运算符(提取后去除引号)
SELECT profile->>'$.city' FROM users;  -- 返回 北京(不带引号)

JSON_CONTAINS:检查是否包含指定值

sql 复制代码
SELECT name FROM users WHERE JSON_CONTAINS(profile->'$.tags', '"developer"');

JSON_SEARCH:搜索 JSON 中的值并返回路径

sql 复制代码
SELECT JSON_SEARCH(profile, 'one', 'developer') FROM users;

JSON_KEYS:获取 JSON 对象的所有键

sql 复制代码
SELECT JSON_KEYS(profile) FROM users;

JSON_LENGTH:获取 JSON 文档的元素个数

sql 复制代码
SELECT name, JSON_LENGTH(profile) FROM users;
SELECT JSON_LENGTH(profile, '$.tags') AS tag_count FROM users;

2.3 JSON 修改函数

JSON_SET:设置或替换值(存在则覆盖,不存在则添加)

sql 复制代码
UPDATE users SET profile = JSON_SET(profile, '$.age', 31, '$.country', '中国')
WHERE name = '张三';

JSON_INSERT:插入新值(如果键已存在则忽略)

sql 复制代码
UPDATE users SET profile = JSON_INSERT(profile, '$.phone', '13800138000')
WHERE name = '张三';

JSON_REPLACE:仅替换已存在的键的值

sql 复制代码
UPDATE users SET profile = JSON_REPLACE(profile, '$.city', '杭州')
WHERE name = '李四';

JSON_REMOVE:删除 JSON 中的键

sql 复制代码
UPDATE users SET profile = JSON_REMOVE(profile, '$.tags') WHERE name = '张三';

JSON_MERGE_PATCH / JSON_MERGE_PRESERVE:合并 JSON 文档

sql 复制代码
SELECT JSON_MERGE_PATCH('{"name": "张三"}', '{"age": 30}') AS merged;
-- 结果: {"name": "张三", "age": 30}

2.4 JSON 创建与验证函数

sql 复制代码
-- 创建 JSON 数组
SELECT JSON_ARRAY('apple', 'banana', 'cherry') AS fruits;

-- 创建 JSON 对象
SELECT JSON_OBJECT('name', '张三', 'age', 30) AS person;

-- 将字符串转换为有效的 JSON
SELECT JSON_QUOTE('Hello "World"');   -- "Hello \"World\""

-- 验证字符串是否为有效的 JSON
SELECT JSON_VALID('{"name": "张三"}'); -- 返回 1
SELECT JSON_VALID('not a json');       -- 返回 0

-- 格式化 JSON 输出(更易读)
SELECT JSON_PRETTY(profile) FROM users;

2.5 JSON 虚拟列与索引优化

为了提高 JSON 字段的查询性能,可以创建虚拟生成列并为其建立索引。

sql 复制代码
-- 添加虚拟生成列(存储邮箱的优化查找列)
ALTER TABLE users ADD COLUMN email VARCHAR(255)
    GENERATED ALWAYS AS (profile->>'$.email') STORED;

-- 为虚拟列建立索引
CREATE INDEX idx_email ON users (email);

-- 查询时使用索引
SELECT * FROM users WHERE email = 'john@example.com';

三、窗口函数(Window Functions)(MySQL 8.0+)

窗口函数是在不分组的情况下,对查询结果集中的每一行执行计算,同时保留原始行的所有信息。

3.1 基础语法

窗口函数的基本语法:函数() OVER ([PARTITION BY 列] [ORDER BY 列] [frame_clause])

  • PARTITION BY:将结果集分区,窗口函数在每个分区内独立计算(相当于 GROUP BY 但不合并行)
  • ORDER BY:定义分区内的排序顺序
  • frame_clause:定义窗口范围(如 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

3.2 排序窗口函数

函数 说明
ROW_NUMBER() 为分区内的每一行分配一个唯一的序号(从 1 开始)
RANK() 排名,相同值排名相同,但会留下空洞(例如:1,2,2,4)
DENSE_RANK() 排名,相同值排名相同,不留空洞(例如:1,2,2,3)
PERCENT_RANK() 百分比排名,返回 (rank-1)/(total rows-1)
CUME_DIST() 累计分布,返回 (<=当前值的行数)/总行数

示例

sql 复制代码
SELECT 
    name, 
    department, 
    salary,
    ROW_NUMBER() OVER (ORDER BY salary DESC) AS global_rank,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees;

3.3 值窗口函数

函数 说明
LAG(expr, offset, default) 返回分区内当前行之前第 offset 行的值
LEAD(expr, offset, default) 返回分区内当前行之后第 offset 行的值
FIRST_VALUE(expr) 返回窗口框架中第一行的值
LAST_VALUE(expr) 返回窗口框架中最后一行的值
NTH_VALUE(expr, N) 返回窗口框架中第 N 行的值

示例

sql 复制代码
SELECT 
    date,
    amount,
    LAG(amount, 1) OVER (ORDER BY date) AS prev_amount,      -- 前一天金额
    LEAD(amount, 1) OVER (ORDER BY date) AS next_amount,     -- 后一天金额
    amount - LAG(amount, 1) OVER (ORDER BY date) AS daily_change
FROM daily_sales;

-- 获取每个部门中薪资最高的人的姓名
SELECT department, name, salary
FROM (
    SELECT *, FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary DESC) AS top_name
    FROM employees
) t;

3.4 聚合函数作为窗口函数

大多数聚合函数(SUM、AVG、COUNT、MAX、MIN)也可以用作窗口函数,无需使用 GROUP BY 即可计算移动统计。

示例

sql 复制代码
-- 计算每个部门的平均薪资(但保留所有行)
SELECT 
    name,
    department,
    salary,
    AVG(salary) OVER (PARTITION BY department) AS dept_avg_salary,
    SUM(salary) OVER (ORDER BY hire_date) AS running_total_salary
FROM employees;

-- 计算移动平均(当前行及其前两行)
SELECT 
    date,
    amount,
    AVG(amount) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS ma3
FROM sales;

四、公用表表达式(CTE)(Common Table Expressions)(MySQL 8.0+)

公用表表达式(CTE)是在单个语句范围内存在的命名临时结果集,可以在同一语句中被多次引用,有助于编写清晰、可读性高的复杂查询。

基本语法

sql 复制代码
WITH cte_name [(列名1, 列名2, ...)] AS (子查询)
[, cte_name2 AS (子查询)...]
SELECT ... FROM cte_name ...;

示例

sql 复制代码
-- 非递归 CTE
WITH it_dept_users AS (
    SELECT id, name, age 
    FROM users 
    WHERE department_id = (SELECT id FROM departments WHERE name = 'IT')
),
active_users AS (
    SELECT * FROM it_dept_users WHERE status = 'active'
)
SELECT * FROM active_users;

-- 在 UPDATE 语句中使用 CTE
WITH avg_salary AS (
    SELECT department_id, AVG(salary) AS avg_sal
    FROM employees GROUP BY department_id
)
UPDATE employees e
JOIN avg_salary a ON e.department_id = a.department_id
SET e.bonus = e.salary * 0.1
WHERE e.salary < a.avg_sal;

4.1 递归 CTE(WITH RECURSIVE)

递归 CTE 常用于处理树形结构数据或生成序列。

语法

sql 复制代码
WITH RECURSIVE cte_name AS (
    初始查询(锚点成员)
    UNION ALL
    递归查询(引用 cte_name 自身)
)
SELECT ... FROM cte_name;

示例

sql 复制代码
-- 生成 1 到 10 的数字序列
WITH RECURSIVE numbers AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM numbers WHERE n < 10
)
SELECT * FROM numbers;

-- 递归查询部门层级结构(员工-经理关系)
WITH RECURSIVE emp_hierarchy AS (
    -- 锚点:从 CEO 开始
    SELECT id, name, manager_id, 1 AS level
    FROM employees WHERE manager_id IS NULL
    UNION ALL
    -- 递归:找到直属下级
    SELECT e.id, e.name, e.manager_id, eh.level + 1
    FROM employees e
    INNER JOIN emp_hierarchy eh ON e.manager_id = eh.id
)
SELECT * FROM emp_hierarchy ORDER BY level, id;

五、分区表管理(Partitioning)

分区是将表的数据按照指定的规则分散存储到多个物理分区文件中,同时逻辑上仍作为一个完整的表被管理。分区可以显著提高大表的查询性能和管理效率。

在 MySQL 9.3 中,分区支持由 InnoDB 和 NDB 存储引擎提供。

5.1 创建分区表

RANGE 分区(最常用)

将数据按连续的区间范围划分到不同的分区。

sql 复制代码
CREATE TABLE orders (
    order_id INT NOT NULL,
    customer_id INT NOT NULL,
    order_date DATE NOT NULL,
    amount DECIMAL(10,2) NOT NULL,
    PRIMARY KEY (order_id, order_date)   -- 分区键必须是主键的一部分
) ENGINE=InnoDB
PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p2022 VALUES LESS THAN (2023),
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION p2025 VALUES LESS THAN (2026),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

LIST 分区

根据离散值的列表进行分区。

sql 复制代码
CREATE TABLE customers (
    id INT NOT NULL,
    name VARCHAR(100),
    region VARCHAR(20),
    PRIMARY KEY (id, region)
)
PARTITION BY LIST COLUMNS (region) (
    PARTITION p_north VALUES IN ('北京', '天津', '沈阳'),
    PARTITION p_south VALUES IN ('上海', '广州', '深圳'),
    PARTITION p_west VALUES IN ('成都', '重庆', '西安')
);

HASH 分区

对分区键应用哈希函数,将数据均匀分布到指定数量的分区。

sql 复制代码
CREATE TABLE logs (
    log_id INT NOT NULL,
    message TEXT,
    created_at DATETIME,
    PRIMARY KEY (log_id, created_at)
)
PARTITION BY HASH (YEAR(created_at))
PARTITIONS 4;

5.2 分区管理操作

添加分区

sql 复制代码
-- 为 RANGE 分区添加新分区
ALTER TABLE orders ADD PARTITION (PARTITION p2026 VALUES LESS THAN (2027));

-- 为 LIST 分区添加新分区
ALTER TABLE regions ADD PARTITION (PARTITION p_new VALUES IN ('新城市'));

删除分区

⚠️ 警告:删除分区的同时会永久删除该分区中的所有数据,且无法通过 DELETE 触发器恢复,请务必谨慎。

sql 复制代码
-- 删除指定分区(会删除分区中的全部数据)
ALTER TABLE orders DROP PARTITION p2022;

-- 清空分区数据但保留分区结构(MySQL 8.0+)
ALTER TABLE orders TRUNCATE PARTITION p2023;

合并/重组分区

sql 复制代码
-- 将多个分区合并为一个
ALTER TABLE orders REORGANIZE PARTITION p2023, p2024 INTO (
    PARTITION p_merged VALUES LESS THAN (2025)
);

-- 拆分单个分区为多个
ALTER TABLE orders REORGANIZE PARTITION p_future INTO (
    PARTITION p2026 VALUES LESS THAN (2027),
    PARTITION p2027 VALUES LESS THAN (2028)
);

分区维护操作

sql 复制代码
-- 重建分区(优化碎片,释放空间)
ALTER TABLE orders REBUILD PARTITION p2024;

-- 优化分区(相当于重建分区 + 分析统计信息)
ALTER TABLE orders OPTIMIZE PARTITION p2024;

-- 分析分区(更新索引统计信息)
ALTER TABLE orders ANALYZE PARTITION p2024;

-- 检查分区(检查数据和索引)
ALTER TABLE orders CHECK PARTITION p2024;

-- 修复分区(修复损坏的分区)
ALTER TABLE orders REPAIR PARTITION p2024;

5.3 查看分区信息

sql 复制代码
-- 查看表的分区信息
SELECT * FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'orders';

-- 查看分区表的定义
SHOW CREATE TABLE orders;

-- 查看分区统计数据
SELECT 
    PARTITION_NAME, 
    PARTITION_METHOD,
    TABLE_ROWS,
    DATA_LENGTH,
    INDEX_LENGTH
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'orders';

六、复制管理高级命令

6.1 组复制插件管理(Group Replication)

安装组复制插件

sql 复制代码
-- 检查插件是否已安装
SHOW PLUGINS;

-- 安装 group_replication 插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';

引导/启动组复制

引导新组用于创建第一个节点的过程。引导操作必须且只能由单个服务器进行一次,且仅执行一次。

sql 复制代码
-- 第一步:在主节点(引导节点)执行
SET GLOBAL group_replication_bootstrap_group = ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group = OFF;

-- 第二步:在其他节点添加
-- 启动时提供分布式恢复所需的用户凭证
START GROUP_REPLICATION USER='rpl_user', PASSWORD='password';

停止组复制

sql 复制代码
STOP GROUP_REPLICATION;

查看组复制状态

sql 复制代码
-- 查看组内所有成员状态
SELECT * FROM performance_schema.replication_group_members;

-- 查看组复制运行状态
SELECT * FROM performance_schema.replication_group_member_stats;

将节点加入/退出组

sql 复制代码
-- 正常加入(节点已经配置好 group_replication 相关参数)
START GROUP_REPLICATION;

-- 退出组
STOP GROUP_REPLICATION;

6.2 InnoDB Cluster 管理(MySQL Shell AdminAPI)

InnoDB Cluster 是 MySQL Group Replication + MySQL Shell + MySQL Router 三者结合的企业级高可用解决方案。使用 MySQL Shell 的 AdminAPI 进行管理。

创建集群(dba.createCluster)

dba.createCluster() 函数用于创建集群,其中被连接的实例作为种子实例,其数据将被复制到后续添加的其他实例上。

sql 复制代码
-- 在 MySQL Shell 中连接到一个 MySQL 实例
mysql-js> \c root@primary-mysql:3306

-- 创建名为 'myCluster' 的集群
mysql-js> var cluster = dba.createCluster('myCluster');

-- 创建集群时指定多主模式(可选,默认为单主模式)
mysql-js> var cluster = dba.createCluster('myCluster', {type: 'multi-primary'});

-- 如果已有 Group Replication 配置,可以从现有组中组建集群
mysql-js> var cluster = dba.createCluster('myCluster', {adoptFromGR: true});

参数说明

  • type:集群模式,可选 'single-primary'(默认)或 'multi-primary'
  • adoptFromGR:是否从现有的 Group Replication 组中组建集群
  • force:强制创建,即使实例配置不标准(慎用)
  • exitStateAction:成员退出时的行为策略
  • memberWeight:成员在主节点选举中的权重

添加实例到集群(addInstance)

sql 复制代码
-- 添加第二个节点
mysql-js> cluster.addInstance('root@secondary-mysql1:3306');

-- 使用指定的恢复方法添加
mysql-js> cluster.addInstance('root@secondary-mysql2:3306', {recoveryMethod: 'clone'});

变量说明recoveryMethod 可选项包括 'clone'(使用克隆插件从主库克隆所有数据)和 'incremental'(仅复制增量数据),两者都需要集群具备相应的权限和环境配置。

查看集群状态(status)

sql 复制代码
-- 查看集群详细状态
mysql-js> cluster.status();

-- 显示扩展信息(包含复制延迟等细节)
mysql-js> cluster.status({extended: 1});

移除实例(removeInstance)

从 InnoDB 集群中删除实例,操作确保将实例从所有 ONLINE 状态的集群成员以及实例本身的元数据中删除。

sql 复制代码
-- 删除指定实例
mysql-js> cluster.removeInstance('root@offline-mysql:3306');

-- 强制删除(即使实例不可达)
mysql-js> cluster.removeInstance('root@offline-mysql:3306', {force: true});

⚠️ 注意:处于 ONLINE 状态的 InnoDB 集群中最后剩下的实例无法使用此操作删除。

重新加入实例(rejoinInstance)

sql 复制代码
-- 让之前离开的实例重新加入集群
mysql-js> cluster.rejoinInstance('root@rejoining-mysql:3306');

解散集群(dissolve)

sql 复制代码
-- 解散整个集群(各实例恢复为独立服务器,不再组成集群)
mysql-js> cluster.dissolve();

-- 强制解散(即使集群状态不正常)
mysql-js> cluster.dissolve({force: true});

切换集群模式

sql 复制代码
-- 从单主模式切换到多主模式
mysql-js> cluster.switchToMultiPrimaryMode();

-- 从多主模式切换到单主模式(可选指定新的主节点)
mysql-js> cluster.switchToSinglePrimaryMode('new-primary-instance:3306');

设置主节点(setPrimaryInstance)

sql 复制代码
-- 在单主模式下指定新的主节点
mysql-js> cluster.setPrimaryInstance('candidate-primary:3306');

配置实例(configureInstance)

sql 复制代码
-- 检查并配置实例使其适用于 InnoDB Cluster
mysql-js> dba.configureInstance('root@instance:3306');

集群管理命令完整列表

方法 说明
dba.createCluster() 创建 InnoDB Cluster
cluster.addInstance() 向集群添加实例
cluster.status() 查看集群状态
cluster.removeInstance() 从集群移除实例
cluster.rejoinInstance() 将实例重新加入集群
cluster.dissolve() 解散集群
cluster.switchToMultiPrimaryMode() 切换到多主模式
cluster.switchToSinglePrimaryMode() 切换到单主模式
cluster.setPrimaryInstance() 设置主节点
cluster.rescan() 重新扫描集群
cluster.describe() 描述集群结构
cluster.listRouters() 列出 Router 实例
dba.configureInstance() 配置实例

6.3 MySQL Router 配置与管理

MySQL Router 是轻量级中间件,用于将客户端连接透明的路由到正确的 MySQL 实例,实现读写分离和负载均衡。Router 的核心功能是连接路由,即将 MySQL 客户端连接重定向到可用的 MySQL 服务器。

安装 MySQL Router

bash 复制代码
# Ubuntu/Debian
sudo apt install mysql-router

# RHEL/CentOS
sudo yum install mysql-router

引导(Bootstrap)配置

mysqlrouter --bootstrap 命令会连接到集群获取拓扑信息并自动生成配置文件。

bash 复制代码
# 引导配置(自动从 InnoDB Cluster 获取拓扑)
sudo mysqlrouter --bootstrap root@primary-mysql:3306 --directory /var/lib/mysqlrouter

# 指定用户凭据
sudo mysqlrouter --bootstrap innoclusteradmin@cluster-node:3306 --user=mysqlrouter

配置文件示例(TOML 格式)

toml 复制代码
# /etc/mysqlrouter/mysqlrouter.conf

[DEFAULT]
logging_folder = /var/log/mysqlrouter

[logger]
level = INFO

# 读写分离路由(写操作路由到主库)
[routing:primary]
bind_port = 6446
destinations = primary-mysql:3306
routing_strategy = first-available

# 读负载均衡路由(读操作均衡分配到从库)
[routing:secondary]
bind_port = 6447
destinations = replica1:3306,replica2:3306,replica3:3306
routing_strategy = round-robin

启动和管理 MySQL Router

bash 复制代码
# 启动 Router(使用系统服务)
sudo systemctl start mysqlrouter

# 查看状态
sudo systemctl status mysqlrouter

# 手动启动 Router(指定配置目录)
mysqlrouter --config /var/lib/mysqlrouter/mysqlrouter.conf &

# 停止 Router
sudo systemctl stop mysqlrouter

# 重启 Router
sudo systemctl restart mysqlrouter

查看 Router 状态

sql 复制代码
-- 在 MySQL Shell 中查看已注册的 Router 实例
mysql-js> cluster.listRouters();

Router 核心配置选项

选项 说明
bind_port Router 监听的端口
destinations 后端 MySQL 服务器列表
routing_strategy 路由策略(first-available 或 round-robin)
mode 路由模式(read-write / read-only)

6.4 复制监控常用查询

查看从库复制延迟详细状态

sql 复制代码
SHOW SLAVE STATUS\G

-- 关键指标解读:
-- Slave_IO_Running: IO线程状态(应始终为 Yes)
-- Slave_SQL_Running: SQL线程状态(应始终为 Yes)
-- Seconds_Behind_Master: 从库落后主库的秒数(0为最佳)
-- Last_IO_Error / Last_SQL_Error: 最近的错误(如有异常需重点关注)

查看组复制成员状态

sql 复制代码
SELECT * FROM performance_schema.replication_group_members;
SELECT * FROM performance_schema.replication_group_member_stats;

查看二进制日志中继日志的空间占用

sql 复制代码
SHOW BINARY LOGS;
SHOW MASTER STATUS;
SHOW SLAVE STATUS\G
-- 查看 Relay_Master_Log_File 和 Relay_Log_Pos 字段

查看等待复制触及位置时出现的事务情况

sql 复制代码
SELECT * FROM information_schema.innodb_trx;
SELECT * FROM performance_schema.replication_applier_status_by_worker;

七、网络连接安全管理

7.1 连接管理与监控

查看当前连接和活动查询

sql 复制代码
-- 查看所有连接的详细信息
SHOW FULL PROCESSLIST;

-- 查看每个连接的详细状态
SELECT * FROM information_schema.processlist;

-- 按时间排序查看运行中的查询
SELECT id, user, host, db, command, time, state, info
FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;

终止连接或查询

使用 KILL 语句终止线程,该线程会收到特定线程的终止标志,可能需要一定时间才会停止。

sql 复制代码
-- 终止指定连接(等价于 KILL 命令不带修饰符)
KILL CONNECTION 123;

-- 仅终止当前正在执行的查询,不关闭连接
KILL QUERY 123;

-- 使用 mysqladmin 命令终止(在操作系统终端)
mysqladmin -u root -p kill 123

⚠️ 注意:终止连接或查询时要谨慎,确认进程是否为正在执行的重要事务。

查看和修改连接相关配置

sql 复制代码
-- 查看最大连接数配置
SHOW VARIABLES LIKE 'max_connections';

-- 查看当前连接数和峰值
SHOW STATUS LIKE 'Threads_connected';
SHOW STATUS LIKE 'Max_used_connections';

-- 动态调整最大连接数(需重启后恢复,建议在 my.cnf 中永久设置)
SET GLOBAL max_connections = 500;

MySQL 会保留一个额外的连接供拥有 CONNECTION_ADMIN 权限的账户使用,以确保管理员始终能够连接并检查系统。

7.2 SSL/TLS 加密连接管理

检查 SSL 是否启用

sql 复制代码
-- 查看 SSL 相关变量
SHOW VARIABLES LIKE '%ssl%';
SHOW VARIABLES LIKE 'have_openssl';      -- 查看是否支持 OpenSSL
SHOW VARIABLES LIKE 'have_ssl';          -- 查看是否启用了 SSL

-- 查看当前连接是否使用 SSL
SHOW STATUS LIKE 'Ssl_cipher';           -- 当前连接使用的加密套件
SHOW STATUS LIKE 'Ssl_version';          -- 当前连接使用的 TLS 版本

服务器端 SSL 配置(my.cnf)

ini 复制代码
[mysqld]
# SSL 证书和密钥配置
ssl-ca = /etc/mysql/ssl/ca-cert.pem
ssl-cert = /etc/mysql/ssl/server-cert.pem
ssl-key = /etc/mysql/ssl/server-key.pem

# 要求客户端使用 SSL(可选,强制所有连接加密)
require_secure_transport = ON

# 指定 TLS 版本
tls_version = TLSv1.2,TLSv1.3

客户端 SSL 连接选项

MySQL 5.7.11 及以后版本的客户端在连接命令中添加 --ssl-mode 选项可以设置 SSL 加密。

bash 复制代码
# 方式1:要求加密连接
mysql -u user -p -h mysqldb.example.com --ssl-mode=REQUIRED

# 方式2:指定 CA 证书进行服务端证书验证
mysql -u user -p -h mysqldb.example.com --ssl-mode=VERIFY_CA --ssl-ca=ca-cert.pem

# 方式3:指定完整的证书验证(双向验证)
mysql -u user -p -h mysqldb.example.com --ssl-mode=VERIFY_IDENTITY \
    --ssl-ca=ca-cert.pem \
    --ssl-cert=client-cert.pem \
    --ssl-key=client-key.pem

# 方式4:MySQL Shell 加密连接
mysql-js> \c --ssl-mode=REQUIRED user@host:3306

SSL 模式说明

模式 说明
PREFERRED 默认行为,尝试加密连接,失败则回退到未加密连接
REQUIRED 必须加密连接,无法建立加密连接则失败
VERIFY_CA 加密连接且验证服务器 CA 证书
VERIFY_IDENTITY 加密连接且验证服务器证书中的主机名

创建要求 SSL 连接的用户

sql 复制代码
-- 创建用户时必须使用 SSL 连接
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL;
ALTER USER 'secure_user'@'%' REQUIRE SSL;

-- 要求 X.509 证书验证
CREATE USER 'cert_user'@'%' IDENTIFIED BY 'password' 
    REQUIRE X509;

查看当前连接的安全状态

sql 复制代码
-- 查看当前会话是否使用 SSL
SELECT SSL_CIPHER, SSL_VERSION;

-- 查看所有连接的加密状态
SELECT 
    id, 
    user, 
    host, 
    connection_type,
    ssl_cipher,
    ssl_version
FROM performance_schema.connection_status;

八、常用系统表监控查询

8.1 使用 Performance Schema 监控

Performance Schema 提供了大量低开销的性能监控数据,是 MySQL 高级监控的核心接口。

sql 复制代码
-- 查看当前活跃连接的状态
SELECT * FROM performance_schema.threads;

-- 查看最近执行的语句
SELECT * FROM performance_schema.events_statements_current;

-- 按语句摘要分组统计(分析执行次数最多的 SQL)
SELECT 
    DIGEST_TEXT,
    COUNT_STAR AS exec_count,
    SUM_TIMER_WAIT / 1000000000 AS total_time_ms,
    AVG_TIMER_WAIT / 1000000000 AS avg_time_ms,
    SUM_ROWS_EXAMINED AS total_rows_examined
FROM performance_schema.events_statements_summary_by_digest
ORDER BY total_time_ms DESC
LIMIT 10;

8.2 使用 INFORMATION_SCHEMA 监控

sql 复制代码
-- 查看表元数据信息
SELECT * FROM information_schema.tables;
SELECT * FROM information_schema.columns WHERE table_name = 'users';

-- 查看存储引擎统计信息
SELECT * FROM information_schema.innodb_trx;                   -- 当前进行中的事务
SELECT * FROM information_schema.innodb_locks;                 -- 当前锁信息
SELECT * FROM information_schema.innodb_lock_waits;           -- 锁等待关系

九、最佳实践总结

类别 原则
存储程序 尽量减少存储过程中的复杂业务逻辑;定期审查和删除不再使用的存储程序;将触发器设计为短小精悍,避免链式触发。
JSON 数据 JSON 字段不适合存储大量结构化数据;对频繁查询的 JSON 值创建虚拟列索引;避免 JSON 嵌套过深(3层以内)。
窗口函数 适当使用移动帧(ROWS/RANGE BETWEEN)来精确控制计算范围;注意 LAST_VALUELEAD 的预定义窗口范围行为。
分区表 单表超过 50GB 或 1000 万行考虑分区;分区键必须是主键或唯一索引的一部分;定期清理或归档旧分区。
网络连接 配置合理的 max_connections(建议不超过内存可支撑的范围),对风险业务连接设置 max_user_connections 限制。
集群与复制 InnoDB Cluster 至少需要 3 个节点;主从复制延迟超过阈值时应及时切换从库。
SSL/TLS 生产环境务必启用 SSL/TLS 加密生产流量;定期轮换证书;使用 REQUIRE SSL 限制用户。

以上是 MySQL 数据库中高级特性与网络管理的全部核心命令,涵盖存储程序(存储过程、函数、触发器、事件)、JSON数据处理、窗口函数、CTE、分区管理、复制架构(Group Replication)、InnoDB Cluster、MySQL Router、SSL/TLS加密连接以及连接管理等内容。根据实际业务需求灵活组合使用即可。

相关推荐
每天进步一点_JL2 小时前
Spring 【多实现切换 & 事务代理机制】深度解析
后端
Gopher_HBo2 小时前
CompletableFuture函数原理
后端
香山上的麻雀10082 小时前
由 Rust 开发的能大幅降低LLM token消耗的高性能 CLI 代理工具 rtk
开发语言·后端·rust
神奇小汤圆2 小时前
Java vs Go:哈希冲突解决之道,为什么一个用红黑树,一个用桶?
后端
神奇小汤圆2 小时前
得物二面:Redis 中某个 Key 访问量特别大怎么办?我:Redis 能顶得住... 生瓜蛋子 生瓜蛋子
后端
掘金者阿豪2 小时前
Spring Data JPA 接入金仓数据库:少写代码,多干活
前端·后端
Moment2 小时前
AI 时代,为什么全栈项目越来越离不开 Monorepo 和 TypeScript
前端·javascript·后端
神奇小汤圆2 小时前
字节一面凉了!被问接口超时频繁,线程池该怎么优化?面试官:你管这叫高并发优化?
后端
Jenlybein3 小时前
用 uv 替代 conda,速度飙升(从 0 到 1 开始使用 uv)
后端·python·算法