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

MySQL中如何对UNION ALL合并数据集做多维度分组及各维度计数

实现方案

两种方案均仅扫描1次原表,避免重复访问大表造成性能损耗。

MySQL 8.0+ 最优方案(窗口函数实现)

核心逻辑:先通过单次表扫描过滤2020年的出行记录,合并出发/目的地数据,再用窗口函数按不同维度聚合计数,无需重复访问原表。

WITH combined_loc AS (
    -- 合并出发地、目的地数据,仅扫描1次trips表
    SELECT o__continent as continent, o__country as country, o__state_name as state, o__city_name as city
    FROM db.trips
    -- 替换函数运算为范围查询,tripdate有索引时可直接命中
    WHERE tripdate >= '2020-01-01' AND tripdate < '2021-01-01'
    UNION ALL
    SELECT d__continent as continent, d__country as country, d__state_name as state, d__city_name as city
    FROM db.trips
    WHERE tripdate >= '2020-01-01' AND tripdate < '2021-01-01'
)
SELECT DISTINCT
    continent,
    country,
    state,
    city,
    -- 按各维度分区统计总出现次数
    COUNT(*) OVER (PARTITION BY continent) AS continent_count,
    COUNT(*) OVER (PARTITION BY continent, country) AS country_count,
    COUNT(*) OVER (PARTITION BY continent, country, state) AS state_count,
    COUNT(*) OVER (PARTITION BY continent, country, state, city) AS city_count
FROM combined_loc;

MySQL 5.x 兼容方案

核心逻辑:先把合并后的数据集存为派生表,再分别按各维度聚合后关联得到结果,全程仅访问1次原表。

SELECT 
    combined_loc.continent,
    combined_loc.country,
    combined_loc.state,
    combined_loc.city,
    continent_cnt.cnt AS continent_count,
    country_cnt.cnt AS country_count,
    state_cnt.cnt AS state_count,
    city_cnt.cnt AS city_count
FROM (
    -- 仅扫描1次原表合并数据
    SELECT o__continent as continent, o__country as country, o__state_name as state, o__city_name as city
    FROM db.trips
    WHERE tripdate >= '2020-01-01' AND tripdate < '2021-01-01'
    UNION ALL
    SELECT d__continent as continent, d__country as country, d__state_name as state, d__city_name as city
    FROM db.trips
    WHERE tripdate >= '2020-01-01' AND tripdate < '2021-01-01'
) AS combined_loc
-- 所有聚合均基于上方合并后的派生表,不会重复访问原表
JOIN (SELECT continent, COUNT(*) AS cnt FROM combined_loc GROUP BY continent) AS continent_cnt USING(continent)
JOIN (SELECT continent, country, COUNT(*) AS cnt FROM combined_loc GROUP BY continent, country) AS country_cnt USING(continent, country)
JOIN (SELECT continent, country, state, COUNT(*) AS cnt FROM combined_loc GROUP BY continent, country, state) AS state_cnt USING(continent, country, state)
JOIN (SELECT continent, country, state, city, COUNT(*) AS cnt FROM combined_loc GROUP BY continent, country, state, city) AS city_cnt USING(continent, country, state, city)
GROUP BY combined_loc.continent, combined_loc.country, combined_loc.state, combined_loc.city;
额外性能优化建议
  • 优先使用范围查询替代YEAR()函数运算,当tripdate字段建有索引时可以直接命中索引,避免全表扫描
  • 可针对查询场景创建联合索引:idx_tripdate_loc (tripdate, o_continent, o_country, o_state, o_city, d_continent, d_country, d_state, d_city),查询时直接走索引覆盖,无需回表读取数据
  • 若该统计为高频查询,可创建定时任务预生成统计结果存入中间表,查询时直接读取中间表即可,无需每次实时计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 11:45:03