说明:高级与网络管理涵盖存储程序(存储过程、函数、触发器、事件)、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 事件发生时自动执行,无需显式调用。执行时机可以为 BEFORE 或 AFTER,作用范围可以是 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_VALUE 和 LEAD 的预定义窗口范围行为。 |
| 分区表 | 单表超过 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加密连接以及连接管理等内容。根据实际业务需求灵活组合使用即可。