安全替换订单统计存储过程需先导出原逻辑并确认参数签名,再新建同名新过程(如p_order_stats_v2)测试通过,最后用rename procedure原子切换;重构时须避免date()等函数导致索引失效,改用pay_time >= in_start_date and pay_time
存储过程里怎么安全替换旧的订单统计逻辑
直接 DROP + CREATE 会中断正在调用的老业务,尤其当应用层没做重试或兜底时,容易触发空结果或报错。必须用原子性替换方案。
- 先用
SHOW CREATE PROCEDURE p_old_order_stats导出原逻辑,确认参数签名(比如是否含OUT参数、是否依赖临时表)- 新建过程用不同名字,如
p_order_stats_v2,把新逻辑完整实现并测试通过- 用
RENAME PROCEDURE原子切换:RENAME PROCEDURE p_old_order_stats TO p_old_order_stats_bak, p_order_stats_v2 TO p_old_order_stats- 切换后立刻验证:
CALL p_old_order_stats('2025-01-01', '2025-01-31');看结果是否与历史一致重构时如何避免 WHERE 条件失效导致全表扫描
老逻辑常写
WHERE DATE(pay_time) = '2025-01-01',这会让索引失效;新过程必须改用范围查询+函数可下推写法。
- 错误写法:
DATE(pay_time) BETWEEN in_start_date AND in_end_date→ 无法走pay_time索引- 正确写法:
pay_time >= in_start_date AND pay_time- 配套检查索引:
SHOW INDEX FROM order_main WHERE Key_name = 'idx_pay_time_status',确保包含pay_time和pay_status- 如果原表没复合索引,先建:
CREATE INDEX idx_pay_time_status ON order_main(pay_time, pay_status)多参数组合查询时怎么防止 NULL 参数引发意外过滤
IN参数传NULL是常见坑——比如店铺ID为空时本意是“不限店铺”,但WHERE shop_id = NULL永远不成立。
- 别用
shop_id = IFNULL(in_shop_id, shop_id),它在某些 MySQL 版本下无法利用索引- 改用显式分支:
AND (in_shop_id IS NULL OR shop_id = in_shop_id)- 注意括号优先级:必须加括号,否则
AND会先于OR执行,导致逻辑错乱- 若字段允许 NULL,且业务上
shop_id = 0表示“无归属”,则统一用0代替NULL传参,避免三值逻辑干扰为什么重构后性能反而下降?重点查这三处
看似逻辑等价,但执行计划可能完全不同。不要只比对结果,要盯住
EXPLAIN FORMAT=TRADITIONAL输出。
- 查是否用了
Using temporary或Using filesort:说明 GROUP BY 没走索引,需补ORDER BY NULL或调整分组字段顺序- 查
rows是否暴涨:比如从 1000 跳到 500000,大概率是 JOIN 或子查询没加驱动表限制- 查
key_len是否变小:比如从 8 降到 4,说明复合索引只用到了前缀列,后面列失效了真实案例中,有团队把
SELECT ... FROM order_main JOIN order_item改成子查询后,因没加STRAIGHT_JOIN,优化器选了错误驱动表,耗时从 0.2s 升到 8s。












