You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化含多SELECT列的MariaDB查询——性能提升方案咨询

优化MariaDB中多子查询统计的方案

你的问题核心在于多次重复扫描全表——原查询对每个选手都执行7次独立的子查询,相当于把25000条数据扫了7遍,这肯定慢。在MariaDB 10.2里,用条件聚合+行转列的方式可以把扫描次数降到最低,是这类统计查询的最优解。

优化后的查询语句

直接用UNION ALL把每个比赛的两个选手拆成单独行,再通过CASE语句做条件聚合,只需要扫描原表两次:

SELECT 
    player,
    COUNT(*) AS since_start_matches,
    SUM(CASE WHEN ht_total_goals = 0 THEN 1 ELSE 0 END) AS since_start_ht_0,
    SUM(CASE WHEN ht_total_goals = 1 THEN 1 ELSE 0 END) AS since_start_ht_1,
    SUM(CASE WHEN ht_total_goals = 2 THEN 1 ELSE 0 END) AS since_start_ht_2,
    SUM(CASE WHEN ht_total_goals = 3 THEN 1 ELSE 0 END) AS since_start_ht_3,
    SUM(CASE WHEN ht_total_goals = 4 THEN 1 ELSE 0 END) AS since_start_ht_4,
    SUM(CASE WHEN ht_total_goals >= 5 THEN 1 ELSE 0 END) AS since_start_ht_5_plus
FROM (
    -- 拆分每个比赛的两个选手为独立行
    SELECT player_1 AS player, ht_total_goals FROM results
    UNION ALL
    SELECT player_2 AS player, ht_total_goals FROM results
) AS player_matches
GROUP BY player
ORDER BY player;

为什么这个方案更快?

  • 原查询:对每个player_1的选手,执行7次全表扫描去匹配player_1或player_2的记录,总扫描量是7 * 25000行。
  • 优化后:只扫描原表两次(UNION ALL的两个分支),然后一次分组聚合完成所有统计,总扫描量仅2 * 25000行,计算逻辑也更高效。

另外,原查询还存在一个逻辑漏洞:会漏掉只出现在player_2列的选手,而优化后的查询会包含所有参与过比赛的选手,结果更完整。

配套索引优化

为了让UNION ALL的两个分支直接用索引覆盖查询(不需要回表读取原数据),可以创建两个针对性的联合索引:

-- 覆盖player_1和ht_total_goals的查询
CREATE INDEX idx_results_p1_ht ON results (player_1, ht_total_goals);
-- 覆盖player_2和ht_total_goals的查询
CREATE INDEX idx_results_p2_ht ON results (player_2, ht_total_goals);

或者创建一个包含所有需要字段的联合索引,也能达到同样效果:

CREATE INDEX idx_results_players_ht ON results (player_1, player_2, ht_total_goals);

添加索引后,这个查询的速度应该能从7秒降到几百毫秒,完全满足性能需求。

内容的提问来源于stack exchange,提问作者arsenal88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 12:02:32