报表下钻踩坑:GROUP_CONCAT 长度限制导致数据丢失,改用 JSON_ARRAYAGG

📅 2026/7/23 21:17:54
报表下钻踩坑:GROUP_CONCAT 长度限制导致数据丢失,改用 JSON_ARRAYAGG
目录一、问题出现二、原因分析三、为什么下钻场景特别容易发现四、解决方案原方案修改方案五、为什么 JSON_ARRAYAGG 更适合下钻六、修改后的 SQL七、注意事项八、总结背景在开发财务报表、欠费分析等统计类功能时经常会有这样的需求汇总页面展示统计数据点击某一行后下钻查看该分类下所有明细数据。例如欠费账龄分析项目A 欠费资源数5000个 欠费金额100000元用户点击项目A需要进入明细页面资源1 资源2 资源3 ... 资源5000实现方式通常是在汇总 SQL 中提前聚合资源 IDGROUP_CONCAT(DISTINCTtmp.fld_object_guid)ASfldObjectGuidsStr然后下钻时wherefld_object_guidin(...)根据这些 ID 查询明细。一、问题出现测试数据量较小时GROUP_CONCAT(DISTINCTfld_object_guid)返回正常10001,10002,10003,10004下钻查询select*fromes_charge_owner_feewherefld_object_guidin(10001,10002,10003,10004)结果正常。但是生产环境某些项目资源量较大例如一个区域 20000个资源执行GROUP_CONCAT(DISTINCTfld_object_guid)发现汇总数量资源数20000但是下钻明细只有几千条二、原因分析查看 SQLGROUP_CONCAT(DISTINCTtmp.fld_object_guid)发现问题。MySQL 对GROUP_CONCAT有长度限制group_concat_max_len默认1024查看SHOWVARIABLESLIKEgroup_concat_max_len;当聚合结果超过限制MySQL 不会报错。而是直接截断后面的内容。例如实际应该1001,1002,1003,1004,1005......9999但是因为超过长度实际返回1001,1002,1003,1004......1200后面的资源 ID 全部丢失。三、为什么下钻场景特别容易发现普通列表可能只是展示资源数量20000用户感觉正常。但是下钻依赖汇总数据 ↓ 资源ID集合 ↓ 明细查询一旦 ID 集合被截断会出现汇总数量 ≠ 下钻数量例如项目汇总资源数下钻资源数项目A200001024业务人员会认为报表数据不准确。实际上统计 SQL 没问题。问题出在资源 ID 聚合阶段。四、解决方案原方案GROUP_CONCAT(DISTINCTtmp.fld_object_guid)ASfldObjectGuidsStr返回10001,10002,10003本质字符串。修改方案使用JSON_ARRAYAGG()修改JSON_ARRAYAGG(tmp.fld_object_guid)ASfldObjectGuidsStr返回[10001,10002,10003]由数据库直接返回数组结构。五、为什么 JSON_ARRAYAGG 更适合下钻下钻本质需要传递一批资源ID它不是文本。它是集合。以前10001,10002,10003实际上是假装数组。现在[10001,10002,10003]数据结构更加匹配。六、修改后的 SQL原SELECTtmp.fld_area_guid,COUNT(DISTINCTtmp.fld_object_guid)ASfldResourceCount,GROUP_CONCAT(DISTINCTtmp.fld_object_guid)ASfldObjectGuidsStrFROMtmpGROUPBYtmp.fld_area_guid;修改SELECTtmp.fld_area_guid,COUNT(DISTINCTtmp.fld_object_guid)ASfldResourceCount,JSON_ARRAYAGG(tmp.fld_object_guid)ASfldObjectGuidsStrFROMtmpGROUPBYtmp.fld_area_guid;七、注意事项如果之前GROUP_CONCAT(DISTINCTid)需要去重。而JSON_ARRAYAGG()本身不支持JSON_ARRAYAGG(DISTINCTid)需要提前去重SELECTfld_area_guid,JSON_ARRAYAGG(fld_object_guid)FROM(SELECTDISTINCTfld_area_guid,fld_object_guidFROMtmp)tGROUPBYfld_area_guid;八、总结这次问题本质不是 SQL 统计错误。而是使用 GROUP_CONCAT 保存大量 ID 集合在下钻场景中触发长度限制导致 ID 被截断。对于报表汇总数据下钻大批量资源查询ID 集合传递不要使用GROUP_CONCAT()建议使用JSON_ARRAYAGG()让数据库返回真正的集合结构避免因为字符串长度限制导致隐藏的数据丢失问题。一句话总结GROUP_CONCAT 适合展示拼接文本不适合承载下钻所需的大规模 ID 集合报表下钻场景应优先考虑 JSON_ARRAYAGG避免因 group_concat_max_len 限制造成明细数据缺失。