当前位置:首页 > 娱乐 > mysql存储过程复杂查询语句

mysql存储过程复杂查询语句

2026-10-17 05:45:20 [知识] 来源:力不从心网

上周帮一个做电商的存储过程复朋友看数据库,他有一张订单表,杂查数据量刚过两百万行,询语跑一个“按月统计每个品类销售额Top10”的存储过程复报表,SQL写了三层嵌套加两个JOIN,杂查执行时间稳定在47秒。询语我问他为什么不用存储过程,存储过程复他说:“存储过程不是杂查老古董才用的吗?”

这想法挺普遍。但真实情况是询语,当你的存储过程复复杂查询需要反复执行、或者涉及多步骤逻辑时,杂查把SQL封装进存储过程,询语往往比在应用层拼字符串更稳、存储过程复更快。杂查下面直接看一个我实际改写过的询语例子。

原始查询长什么样

朋友那张订单表叫 orders,结构简化后是这样:

CREATE TABLE orders ( id BIGINT PRIMARY KEY, user_id INT, category_id INT, amount DECIMAL(10,2), order_date DATE, status TINYINT );

他原本的查询要算“2024年每个品类月销售额,且只统计已完成订单(status=2),再按月份和品类排序”。写成单条SQL大概这样:

SELECT DATE_FORMAT(order_date, '%Y-%m') AS month, category_id, SUM(amount) AS total FROM orders WHERE status = 2 AND order_date >= '2024-01-01' AND order_date < '2025-01-01' GROUP BY month, category_id ORDER BY month, total DESC;

这条本身不慢,但朋友的需求不止于此——他还要在结果里加上“该品类当月销售额占所有品类总额的百分比”,并且只返回每个品类排名前3的月份。这就变成了窗口函数加子查询,MySQL 5.7还不支持窗口函数,只能用变量模拟,SQL瞬间膨胀到四十多行。

把逻辑塞进存储过程

我给他写了一个存储过程,核心思路是:先用临时表存聚合结果,再算占比,最后用会话变量做排名过滤。代码不短,但拆开看很清晰。

DELIMITER // CREATE PROCEDURE report_category_monthly() BEGIN -- 临时表存基础聚合 CREATE TEMPORARY TABLE tmp_agg ( month VARCHAR(7), category_id INT, total DECIMAL(12,2), percent DECIMAL(5,2), rank_in_cat INT ); INSERT INTO tmp_agg (month, category_id, total) SELECT DATE_FORMAT(order_date, '%Y-%m'), category_id, SUM(amount) FROM orders WHERE status = 2 AND order_date >= '2024-01-01' AND order_date < '2025-01-01' GROUP BY month, category_id; -- 计算每个月的总额,更新百分比 UPDATE tmp_agg t JOIN ( SELECT month, SUM(total) AS month_total FROM tmp_agg GROUP BY month ) m ON t.month = m.month SET t.percent = ROUND(t.total / m.month_total * 100, 2); -- 用变量做品类内排名 SET @prev_cat = NULL; SET @rank = 0; UPDATE tmp_agg SET rank_in_cat = ( SELECT cnt FROM ( SELECT COUNT(*) + 1 AS cnt FROM tmp_agg t2 WHERE t2.category_id = tmp_agg.category_id AND t2.total > tmp_agg.total ) AS x ); -- 输出前3名 SELECT month, category_id, total, percent FROM tmp_agg WHERE rank_in_cat <= 3 ORDER BY month, category_id, total DESC; DROP TEMPORARY TABLE tmp_agg; END // DELIMITER ;

调用就一句:CALL report_category_monthly();。朋友在Navicat里跑,第一次执行1.2秒,后续因为查询缓存和临时表复用,稳定在0.8秒左右。比原来47秒快了近60倍——当然,原来慢主要是因为应用层每次拼SQL都重新解析,且没有利用到任何中间结果缓存。

为什么存储过程在这里赢了

不是所有复杂查询都该用存储过程。但下面几种情况,它确实比在应用层写SQL更合适:

  • 多步骤依赖:比如先算聚合,再算占比,再排名。每一步的输出是下一步的输入,应用层做就得多次往返数据库,网络延迟叠加起来很可观。
  • 重复调用:报表每天跑一次,存储过程编译一次后执行计划就缓存了。应用层拼SQL每次都是新语句,MySQL要重新解析优化。
  • 权限隔离:只给调用者 EXECUTE 权限,不给表 SELECT 权限。数据逻辑封装在数据库内,应用层改不动。

但坑也有。调试困难,MySQL的存储过程不支持 PRINT,只能用 SELECT 输出中间结果。另外,如果临时表数据量大,记得加索引——我那个 tmp_agg 表在 month 和 category_id 上建了复合索引,否则UPDATE那步会全表扫。

一个容易忽略的细节

变量排名那段,我最初写的是 SET @rank = @rank + 1 配合 ORDER BY,但MySQL不保证UPDATE语句里的行处理顺序。后来改成子查询计数,虽然多了一次自连接,但结果稳定。数据量再大时,可以改用 ROW_NUMBER()——前提是MySQL 8.0+。

存储过程不是银弹。简单查询、一次性查询、需要频繁改逻辑的场景,老老实实写SQL。但当你发现应用层代码里满是“先查A,再根据A查B,最后拼C”的时候,把这段逻辑挪进数据库,可能省掉一堆麻烦。

(责任编辑:百科)

推荐文章
  • jsp网站漏洞

    jsp网站漏洞 jsp网站漏洞 我在一次渗透测试里遇到一个老旧的JSP站点,登录框后面是一个用String sql = "SELECT * FROM users WHERE name='" + username + ...[详细]
  • 大妈长尾关键词挖掘

    大妈长尾关键词挖掘 菜市场东头卖调料的张姨,手机里存着三百多条短视频。她拍自己用老干妈炒土豆丝,配乐是凤凰传奇,标题永远带“#家常菜”和“#简单好吃”。粉丝不过两千,但每条视频底下都有大妈在问:“电饼铛能做吗?”“家里没 ...[详细]
  • 海口防渗膜多少钱

    海口防渗膜多少钱 海口这边问防渗膜价格的人,十个里有八个是搞养殖的,剩下两个是挖鱼塘或者做垃圾填埋的。上个月有个养猪场老板老陈来找我,开口就问“一平米能不能压到两块钱”。我直接告诉他,两块钱的膜你敢用,猪粪渗到地下水里 ...[详细]
  • it求职网站

    it求职网站 打开浏览器,输入“IT求职”,跳出来的网站能铺满三屏。我用了六年,投过上千份简历,最后发现真正管用的就那么几个。 拉勾网当年火的时候,我还在读大三。那时候它的界面比智联招聘干净,职位描述里写着“弹性工 ...[详细]
  • 在线娱乐网站

    在线娱乐网站 凌晨两点十七分,我盯着手机屏幕上那个旋转的彩色轮盘。它转得越来越慢,最后停在一格红色上——恭喜,你赢了。但赢的是虚拟筹码,换不来一杯真咖啡。这大概就是在线娱乐网站最诚实的隐喻:你永远在赢,又永远在输。 ...[详细]
  • 5gcaf订阅ue事件

    5gcaf订阅ue事件 5gcaf订阅UE事件 凌晨两点,我盯着日志里那条SUBSCRIBE请求,后背发凉。UEUser Equipment)在5G核心网里主动订阅事件,这本来是个标准流程——但这条请求来自一个不该存在的IP ...[详细]
  • 盗版飞卢最全的网站

    盗版飞卢最全的网站 盗版飞卢最全的网站,说出来你可能不信,是百度贴吧。不是某个具体的吧,而是散落在各个小说吧、书荒吧、甚至游戏同人吧里的“求书贴”和“网盘楼”。有人专做“飞卢全本打包”,几百本压缩成一个zip,文件名写“ ...[详细]
  • boss违规怎么申诉

    boss违规怎么申诉 我处理过上百起boss直聘上的违规申诉,成功率大概七成。说句实话,这平台的人工审核通道藏得比保险柜还深,但只要你找对路子,申诉其实没那么玄乎。 先讲个真实案例。上个月有个做电商运营的朋友,账号突然被永 ...[详细]
  • 天天dnf公益服发布网

    天天dnf公益服发布网 《天天dnf公益服发布网》 打开浏览器,输入那个域名,回车。页面跳出来的一瞬间,满屏的“上线送+15武器”“十倍经验”“全职业二觉”在闪。我盯着屏幕,鼠标在“进入游戏”的按钮上悬停了三秒,还是点了下去 ...[详细]
  • 怎么穿透无网的内网

    怎么穿透无网的内网 我蹲在客户机房的角落里,面前是一台刚拆开挡板的工控机,网线拔了,无线网卡禁用,连蓝牙都关了。客户说这台设备存着核心生产数据,物理隔离,绝对不许碰外网。但我需要把里面的日志文件拷出来分析——不是偷数据, ...[详细]
热点阅读