热门角色不仅是灵感来源,更是你的效率助手。通过精挑细选的角色提示词,你可以快速生成高质量内容、提升创作灵感,并找到最契合你需求的解决方案。让创作更轻松,让价值更直接!
我们根据不同用户需求,持续更新角色库,让你总能找到合适的灵感入口。
非SARGable谓词
N+1 型相关子查询
重复扫描与不必要的计算
临时表管理与索引
统计口径与可优化点
谓词与语义
去除相关子查询,改为分组一次性聚合+JOIN
临时表与索引
基表索引建议(一次性执行)
其他
以下为等价语义的重构版(MySQL 8+),去除了相关子查询,修复谓词,按阶段性聚合,显式索引临时表。
原始关键片段(问题点示例):
优化后完整过程: DELIMITER // CREATE PROCEDURE sp_order_summary( IN p_shop_id BIGINT, IN p_start_date DATETIME, IN p_end_date DATETIME, IN p_limit INT ) BEGIN DECLARE v_start DATE; DECLARE v_end DATE; DECLARE v_limit INT;
SET v_limit = IFNULL(p_limit, 500);
SET v_start = DATE(IFNULL(p_start_date, NOW() - INTERVAL 30 DAY));
SET v_end = DATE(IFNULL(p_end_date, NOW()));
IF v_end < v_start THEN
SET v_end = v_start;
END IF;
-- 1) 候选订单集(时间窗 + 可选店铺)
DROP TEMPORARY TABLE IF EXISTS tmp_orders;
IF p_shop_id IS NULL THEN
CREATE TEMPORARY TABLE tmp_orders AS
SELECT o.id AS order_id, o.user_id, o.created_at, o.status
FROM orders o
WHERE o.created_at >= v_start
AND o.created_at < v_end + INTERVAL 1 DAY;
ELSE
CREATE TEMPORARY TABLE tmp_orders AS
SELECT o.id AS order_id, o.user_id, o.created_at, o.status
FROM orders o
WHERE o.shop_id = p_shop_id
AND o.created_at >= v_start
AND o.created_at < v_end + INTERVAL 1 DAY;
END IF;
ALTER TABLE tmp_orders
ADD PRIMARY KEY (order_id),
ADD KEY idx_tmp_orders_user (user_id),
ADD KEY idx_tmp_orders_created (created_at);
-- 2) 订单商品聚合(一次性按订单聚合)
DROP TEMPORARY TABLE IF EXISTS tmp_oi_agg;
CREATE TEMPORARY TABLE tmp_oi_agg AS
SELECT
oi.order_id,
COUNT(*) AS item_count,
SUM(oi.quantity) AS total_qty,
SUM(oi.quantity * oi.price) AS total_amount
FROM order_items oi
JOIN tmp_orders t ON t.order_id = oi.order_id
GROUP BY oi.order_id;
ALTER TABLE tmp_oi_agg ADD PRIMARY KEY (order_id);
-- 3) 订单状态日志聚合(一次性取每单最新状态时间)
DROP TEMPORARY TABLE IF EXISTS tmp_status_agg;
CREATE TEMPORARY TABLE tmp_status_agg AS
SELECT
l.order_id,
MAX(l.created_at) AS last_status_change
FROM order_status_log l
JOIN tmp_orders t ON t.order_id = l.order_id
GROUP BY l.order_id;
ALTER TABLE tmp_status_agg ADD PRIMARY KEY (order_id);
-- 4) 用户在时间窗内的订单数与GMV(可选,GMV如不需要可省略以进一步降负)
DROP TEMPORARY TABLE IF EXISTS tmp_user_metric;
CREATE TEMPORARY TABLE tmp_user_metric AS
SELECT
t.user_id,
COUNT(*) AS order_cnt,
SUM(COALESCE(i.total_amount,0)) AS gm_value
FROM tmp_orders t
LEFT JOIN tmp_oi_agg i ON i.order_id = t.order_id
GROUP BY t.user_id;
ALTER TABLE tmp_user_metric ADD PRIMARY KEY (user_id);
-- 5) 用户全量取消单数(仅针对候选用户集合统计)
DROP TEMPORARY TABLE IF EXISTS tmp_cancel_cnt;
CREATE TEMPORARY TABLE tmp_cancel_cnt AS
SELECT u.user_id, COUNT(*) AS cancel_cnt
FROM orders o
JOIN tmp_user_metric u ON u.user_id = o.user_id
WHERE o.status = 'CANCELLED'
GROUP BY u.user_id;
ALTER TABLE tmp_cancel_cnt ADD PRIMARY KEY (user_id);
-- 6) 最终结果
SELECT
t.order_id,
t.user_id,
t.created_at,
t.status,
COALESCE(i.item_count, 0) AS item_count,
COALESCE(i.total_qty, 0) AS total_qty,
COALESCE(i.total_amount, 0) AS order_amount,
COALESCE(u.order_cnt, 0) AS order_cnt,
COALESCE(c.cancel_cnt, 0) AS cancel_cnt,
s.last_status_change
FROM tmp_orders t
LEFT JOIN tmp_oi_agg i ON i.order_id = t.order_id
LEFT JOIN tmp_user_metric u ON u.user_id = t.user_id
LEFT JOIN tmp_cancel_cnt c ON c.user_id = t.user_id
LEFT JOIN tmp_status_agg s ON s.order_id = t.order_id
ORDER BY t.created_at DESC
LIMIT v_limit;
-- 7) 清理
DROP TEMPORARY TABLE IF EXISTS tmp_cancel_cnt;
DROP TEMPORARY TABLE IF EXISTS tmp_user_metric;
DROP TEMPORARY TABLE IF EXISTS tmp_status_agg;
DROP TEMPORARY TABLE IF EXISTS tmp_oi_agg;
DROP TEMPORARY TABLE IF EXISTS tmp_orders;
END // DELIMITER ;
一次性索引(在业务低峰期执行):
去除相关子查询:
谓词可索引化:
临时表索引化:
资源节省:
注:具体收益需基于你的数据分布、并发与硬件进行 EXPLAIN/EXPLAIN ANALYZE 与基准验证。
正确性与回归
会话与临时表
索引上线
参数与边界
监控与回滚
以上方案遵循 MySQL 最佳实践:去函数化谓词、避免 OR 导致的索引失效、用一次性聚合替代相关子查询、为临时表添加索引与减少重复扫描,通常可获得显著且稳定的性能提升。
游标与标量函数逐行调用
非SARGable时间过滤
NOLOCK 的数据一致性风险
临时表与ORDER BY
并发与重复结算风险
索引使用不明确
结构性优化(代码简化与集合化处理)
UDF调用优化
并发与一致性
索引优化(示例DDL)
参数敏感性
下方提供两种等价的集合化实现。优先推荐“单语句更新+输出”版本(更简洁、原子性好)。
CREATE OR ALTER PROCEDURE dbo.SettleTransactions
@BatchDate DATE,
@MerchantId BIGINT = NULL
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @feeRate DECIMAL(5,4) = 0.005;
DECLARE @EndOfDay DATETIME = DATEADD(DAY, 1, @BatchDate);
BEGIN TRAN;
-- 集合化:更新未结算交易并将结果写入台账
UPDATE t
SET t.settled = 1,
t.settle_batch_date = @BatchDate
OUTPUT
inserted.id AS tx_id,
inserted.merchant_id,
inserted.amount AS gross_amount,
f.fee AS fee,
inserted.amount - f.fee AS net_amount,
@BatchDate AS settle_date
INTO dbo.settlement_ledger (tx_id, merchant_id, gross_amount, fee, net_amount, settle_date)
FROM dbo.payment_tx AS t WITH (UPDLOCK, ROWLOCK)
CROSS APPLY (SELECT dbo.fn_calc_fee(t.amount, t.pay_channel, @feeRate) AS fee) AS f
WHERE t.settled = 0
AND t.tx_time < @EndOfDay
AND (@MerchantId IS NULL OR t.merchant_id = @MerchantId)
AND EXISTS (SELECT 1 FROM dbo.payment_tx_detail AS d WHERE d.tx_id = t.id);
-- 可按需评估 OPTION (RECOMPILE)
COMMIT TRAN;
-- 汇总报表
SELECT
m.merchant_name,
COUNT(*) AS tx_cnt,
SUM(l.gross_amount) AS total_amt,
SUM(l.fee) AS total_fee
FROM dbo.settlement_ledger AS l
JOIN dbo.merchant AS m ON m.id = l.merchant_id
WHERE l.settle_date = @BatchDate
GROUP BY m.merchant_name
ORDER BY total_amt DESC;
END
CREATE OR ALTER PROCEDURE dbo.SettleTransactions
@BatchDate DATE,
@MerchantId BIGINT = NULL
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @feeRate DECIMAL(5,4) = 0.005;
DECLARE @EndOfDay DATETIME = DATEADD(DAY, 1, @BatchDate);
DECLARE @SettledIds TABLE (id BIGINT PRIMARY KEY);
BEGIN TRAN;
INSERT INTO dbo.settlement_ledger (tx_id, merchant_id, gross_amount, fee, net_amount, settle_date)
OUTPUT inserted.tx_id INTO @SettledIds(id)
SELECT
t.id,
t.merchant_id,
t.amount,
f.fee,
t.amount - f.fee,
@BatchDate
FROM dbo.payment_tx AS t
CROSS APPLY (SELECT dbo.fn_calc_fee(t.amount, t.pay_channel, @feeRate) AS fee) AS f
WHERE t.settled = 0
AND t.tx_time < @EndOfDay
AND (@MerchantId IS NULL OR t.merchant_id = @MerchantId)
AND EXISTS (SELECT 1 FROM dbo.payment_tx_detail AS d WHERE d.tx_id = t.id);
UPDATE t
SET t.settled = 1,
t.settle_batch_date = @BatchDate
FROM dbo.payment_tx AS t
JOIN @SettledIds AS s ON s.id = t.id;
COMMIT TRAN;
SELECT
m.merchant_name,
COUNT(*) AS tx_cnt,
SUM(l.gross_amount) AS total_amt,
SUM(l.fee) AS total_fee
FROM dbo.settlement_ledger AS l
JOIN dbo.merchant AS m ON m.id = l.merchant_id
WHERE l.settle_date = @BatchDate
GROUP BY m.merchant_name
ORDER BY total_amt DESC;
END
说明:
A. 将日期函数改写为可走索引的范围谓词
B. 基表索引设计(优先级从高到低)
C. 临时表索引与统计信息
D. 连接与半连接写法
E. 报表目标表(可选)
仅展示与索引生效相关的重写(范围谓词、JOIN、临时表索引与ANALYZE);业务逻辑保持不变。
-- 推荐的永久索引(一次性部署,使用 CONCURRENTLY 降低锁影响) CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_created ON users (created_at); -- 或:如果 segment 过滤选择性更强,改为: -- CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_segment_created ON users (segment, created_at);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_sessions_start_time_user ON sessions (start_time, user_id) INCLUDE (duration);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_orders_created_user ON orders (created_at, user_id) INCLUDE (status, amount);
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_events_user_occ_desc ON events (user_id, occurred_at DESC);
-- 可选(报表成品表避免重复) -- CREATE UNIQUE INDEX IF NOT EXISTS ux_daily_user_report ON daily_user_report(date_key, user_id);
-- 存储过程(仅展示核心SQL的“前后对比式”重构) CREATE OR REPLACE PROCEDURE sp_daily_user_report(p_date DATE, p_segment TEXT DEFAULT 'all') LANGUAGE plpgsql AS $$ BEGIN -- 1) tmp_users:改写时间谓词为范围,避免对列使用函数;必要时建索引与ANALYZE CREATE TEMP TABLE tmp_users AS SELECT u.id AS user_id, u.created_at, u.segment, u.region FROM users u WHERE u.created_at < p_date + interval '1 day' AND (p_segment = 'all' OR u.segment = p_segment);
CREATE INDEX ON tmp_users(user_id);
ANALYZE tmp_users;
-- 2) tmp_sessions:改为范围谓词 + 显式JOIN
CREATE TEMP TABLE tmp_sessions AS
SELECT s.user_id,
count(*) AS session_cnt,
sum(s.duration) AS total_duration
FROM sessions s
JOIN tmp_users tu ON tu.user_id = s.user_id
WHERE s.start_time >= p_date
AND s.start_time < p_date + interval '1 day'
GROUP BY s.user_id;
CREATE UNIQUE INDEX ON tmp_sessions(user_id);
ANALYZE tmp_sessions;
-- 3) tmp_orders:范围谓词 + JOIN
CREATE TEMP TABLE tmp_orders AS
SELECT o.user_id,
count(*) FILTER (WHERE o.status='PAID') AS paid_cnt,
sum(o.amount) FILTER (WHERE o.status='PAID') AS gm_value,
sum(o.amount) AS order_amt
FROM orders o
JOIN tmp_users tu ON tu.user_id = o.user_id
WHERE o.created_at >= p_date
AND o.created_at < p_date + interval '1 day'
GROUP BY o.user_id;
CREATE UNIQUE INDEX ON tmp_orders(user_id);
ANALYZE tmp_orders;
-- 4) tmp_last_event:范围谓词 + JOIN
-- 若业务允许放弃随机并列打散,可去掉 random(),显著提升利用 idx_events_user_occ_desc 的能力
CREATE TEMP TABLE tmp_last_event AS
SELECT DISTINCT ON (e.user_id)
e.user_id, e.event_name, e.occurred_at
FROM events e
JOIN tmp_users tu ON tu.user_id = e.user_id
WHERE e.occurred_at >= p_date
AND e.occurred_at < p_date + interval '1 day'
ORDER BY e.user_id, e.occurred_at DESC, random(); -- 如可移除 random(),更佳
CREATE UNIQUE INDEX ON tmp_last_event(user_id);
ANALYZE tmp_last_event;
-- 5) 最终装载
INSERT INTO daily_user_report(date_key, user_id, segment, session_cnt, total_duration, paid_orders, gm_value, last_event, last_event_time)
SELECT
p_date,
u.user_id,
u.segment,
COALESCE(s.session_cnt,0),
COALESCE(s.total_duration,0),
COALESCE(o.paid_cnt,0),
COALESCE(o.gm_value,0),
le.event_name,
le.occurred_at
FROM tmp_users u
LEFT JOIN tmp_sessions s ON s.user_id = u.user_id
LEFT JOIN tmp_orders o ON o.user_id = u.user_id
LEFT JOIN tmp_last_event le ON le.user_id = u.user_id;
RAISE NOTICE 'Report loaded for %, segment=%', p_date, p_segment;
DROP TABLE IF EXISTS tmp_last_event;
DROP TABLE IF EXISTS tmp_orders;
DROP TABLE IF EXISTS tmp_sessions;
DROP TABLE IF EXISTS tmp_users;
END; $$;
综合估计:在数据量较大的在线业务中,上述改造通常可带来数量级的查询时间缩短(例如从秒级/十秒级降至百毫秒-秒级,视数据量与硬件而定),并显著降低缓冲命中压力与I/O。
让 AI 扮演资深数据库优化顾问,面向电商订单、财务结算、报表统计、用户分析等高频业务,专注提升 SQL 存储过程的执行效率与稳定性。通过标准化的诊断流程,完成从问题定位—成因分析—优化方案—重构示例—收益评估—上线注意事项的全链路交付。在不改变业务逻辑的前提下,帮助团队显著缩短响应时间、降低资源消耗、减少扩容支出,并沉淀可复用的优化规范与最佳实践。用户只需粘贴存储过程代码、说明优化目标与数据库类型,即可获得定制化、可直接落地的优化建议与代码片段。最终实现性能与成本的双向提升,让关键流程跑得更快、更稳、更省钱。
快速审计现有存储过程,定位慢点与热点,产出索引与参数调整方案,给出实施与回滚计划,在不影响业务的前提下稳步提速。
在功能迭代中一键审查存储过程,获取可直接套用的重写示例与注意事项,减少反复试错与手工调优时间,缩短上线周期。
评估关键链路数据库负载,设定性能目标并获得取舍建议,沉淀统一的优化规范与评审模板,提升跨团队协作效率。
将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。
把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。
在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。
一次支付永久解锁,全站资源与持续更新;商业项目无限次使用