存储过程与函数是什么
存储过程与存储函数把一段 SQL 逻辑存放在服务端,由客户端用 CALL 或表达式中调用。适合的场景是批量作业与数据迁移:一次调用执行多步语句,省掉多次网络往返,也便于把调度入口固定下来。代价同样明确:调试只能靠行号与自定义日志、版本管理与代码评审困难、在不同数据库之间几乎不可移植,所以核心业务逻辑仍建议留在应用层。
基本信息
| 创建过程 | CREATE PROCEDURE 名(IN/OUT/INOUT 参数 ...) BEGIN ... END |
|---|---|
| 创建函数 | CREATE FUNCTION 名(参数) RETURNS 类型 ... 需声明 DETERMINISTIC 等特性 |
| 调用 | CALL 过程名(参数);函数直接在 SELECT 中使用 |
| 分隔符 | 定义体前用 DELIMITER 临时换分隔符,避免分号提前截断 |
| 查看与删除 | SHOW CREATE PROCEDURE / SHOW PROCEDURE STATUS;DROP PROCEDURE |
典型使用场景
- 批量数据处理:按天数归档、批量状态流转这类多步操作用一次调用完成
- 数据迁移辅助:把数据清洗与搬移逻辑固化在库里,运维直接调用而非手工执行长脚本
- 权限收敛执行入口:只授予 EXECUTE 权限,避免开放底层表的直接写权限
- 回归脚本固化:把数据准备步骤封装成过程,测试环境一键重建数据
- 定时任务入口:事件调度或外部调度器只调用一个过程名,减少脚本维护成本
定义与调用
定义与调用
-- 必须临时改分隔符,否则过程体里的分号会提前结束定义
DELIMITER $$
CREATE PROCEDURE sp_close_orders(IN p_days INT)
BEGIN
UPDATE orders SET status = 'closed'
WHERE status = 'pending' AND created_at < NOW() - INTERVAL p_days DAY;
SELECT ROW_COUNT() AS affected; -- 返回受影响行数便于核对
END$$
DELIMITER ;
CALL sp_close_orders(30);
-- 查看与管理
SHOW CREATE PROCEDURE sp_close_orders\G
DROP PROCEDURE sp_close_orders;过程与函数对比
| 维度 | 存储过程 | 存储函数 |
|---|---|---|
| 调用方式 | CALL 名(参数) | 在 SQL 表达式中调用 |
| 返回值 | 通过 OUT 参数或多个结果集 | 必须 RETURN 一个值 |
| 可用语句 | 支持事务控制与多语句 | 受限,不能随意提交事务 |
| 创建特性 | 无额外要求 | 需声明 DETERMINISTIC 等,否则复制环境可能报错 |
| 典型用途 | 批量作业入口 | 字段计算与转换 |
创建时忘记换分隔符是最常见的新手错误:过程体遇到第一个分号就被截断,报语法错误。定义前先执行 DELIMITER $$,定义结束再换回分号。
带 Binlog 的复制环境中创建存储函数需要正确声明特性(如 DETERMINISTIC、READS SQL DATA 等),否则在主库创建可能直接失败。涉及复制的环境要在主库先验证创建语句。