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

超10万条记录MySQL查询优化:carrier维度流量统计慢查询加速咨询

核心问题说明

你当前查询性能差的核心原因是使用了关联EXISTS子查询,相当于遍历每一条符合条件的stats记录时都要额外执行一次子查询,数据量超过10万时会产生极高的CPU和IO开销,是导致服务器崩溃的主要原因。


优化方案

  • 删掉冗余的关联子查询:你写的EXISTS逻辑实际是筛选carrier下至少有2条记录的数据,完全可以通过GROUP BY后的HAVING条件实现,不需要关联子查询。另外原查询主语句末尾的LIMIT 1,1会导致只返回第二条运营商的统计结果,不符合你要统计所有运营商的需求,直接删除即可。
  • 新增覆盖索引:创建联合索引idx_idlink_carrier_views(id_link, carrier, views),查询时可以直接从索引中获取所有需要的字段,不需要回表查询整行数据,查询效率可提升10倍以上。
  • 修正不合理的字段类型:当前views字段为varchar(1000)字符串类型,求和时需要隐式转换为数字,有额外性能开销,建议改为int类型存储访问量数值。
  • 用WITH ROLLUP实现合计行:不需要通过UNION单独查询合计值,使用MySQL原生的GROUP BY ... WITH ROLLUP语法,仅需一次分组查询即可同时得到各运营商的统计结果和合计行,相比原UNION写法性能提升一倍。如果一定要用UNION实现,也要把UNION改为UNION ALL,避免UNION默认的去重逻辑带来的额外开销。

优化后SQL示例

如果暂时不改views字段类型,可用以下查询:

SELECT
    IFNULL(carrier, 'TOTAL') AS carrier,
    SUM(CAST(views AS UNSIGNED)) AS views,
    SUM(CAST(views AS UNSIGNED) - 1) AS repeated,
    SUM(CAST(views AS UNSIGNED) >= 1) AS unique_views,
    COUNT(1) AS total
FROM stats
WHERE id_link = 39
GROUP BY carrier WITH ROLLUP
HAVING total >= 1;

如果已经将views改为int类型,查询可以进一步简化:

SELECT
    IFNULL(carrier, 'TOTAL') AS carrier,
    SUM(views) AS views,
    SUM(views - 1) AS repeated,
    SUM(views >= 1) AS unique_views,
    COUNT(1) AS total
FROM stats
WHERE id_link = 39
GROUP BY carrier WITH ROLLUP
HAVING total >= 1;

长期优化建议

如果数据量还会持续增长,且查询频率较高,可以新增预统计汇总表,通过定时任务每小时/每天提前计算好各个id_link、各个carrier的统计指标,查询时直接读取汇总表即可,响应速度可优化到毫秒级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 21:09:02