array_agg 本身不比 string_agg 显著慢,真正拖慢的是后续处理;空分隔符有风险;json_agg 比 array_agg 慢1.5–3倍;ORDER BY 在 array_agg 中非必须但几乎总应显式指定。

array_agg 会显著拖慢查询速度吗?
在大多数场景下,array_agg 本身不比 string_agg 慢多少,真正拖慢的是后续对聚合结果的处理——比如你在应用层还要遍历、反序列化或做 JSON 转换。PostgreSQL 内部对两种函数都做了优化,底层都走相同的聚合框架,但 array_agg 需额外维护元素类型信息和内存结构,尤其当元素是复合类型(如 ROW 或嵌套数组)时,开销会上升明显。
实操建议:
- 如果只用于传输或展示,且客户端能直接消费数组(如 Python 的
psycopg2默认返回list),array_agg更安全、无歧义 - 若字段含特殊字符(如逗号、双引号、换行),
string_agg需手动转义,否则解析易出错;这时表面快,实际埋坑 - 用
EXPLAIN (ANALYZE, BUFFERS)对比两者执行计划,重点关注Aggregate节点的Actual Total Time和Buffers消耗,别只看“快几毫秒”
string_agg 的分隔符选空字符串有风险吗?
有,而且很常见。用 string_agg(col, '') 看似省事,但一旦 col 是 TEXT 且含 NULL,整个结果就变 NULL(因为 string_agg 默认跳过 NULL,但空分隔符下无法区分“全 NULL”和“空字符串拼接”)。更麻烦的是,它彻底丢失原始行边界——你无法还原哪几个值原属同一组。
实操建议:
- 永远显式处理
NULL:改用string_agg(COALESCE(col::text, 'NULL'), ',') - 避免空分隔符;若真需无缝拼接(如拼 SQL 片段),优先考虑
array_agg+ 应用层''.join() -
string_agg在 GROUP BY 大量小字符串时内存更省,但一旦单组超 1MB,可能触发临时文件写入,反而比array_agg慢
JSON 聚合比 array_agg 更慢?
是的,json_agg(或 jsonb_agg)通常比 array_agg 慢 1.5–3 倍,因为它要执行类型推断、引号包裹、转义、编码验证。但注意:这不是“数组 vs 字符串”的问题,而是“裸数组 vs 序列化结构”的问题。如果你本就要返回 JSON 给前端,那提前在数据库里做 jsonb_agg 反而减少应用层序列化压力。
云点滴客户解决方案是针对中小企业量身制定的具有简单易用、功能强大、永久免费使用、终身升级维护的智能化客户解决方案。依托功能强大、安全稳定的阿里云平 台,性价比高、扩展性好、安全性高、稳定性好。高内聚低耦合的模块化设计,使得每个模块最大限度的满足需求,相关模块的组合能满足用户的一系列要求。简单 易用的云备份使得用户随时随地简单、安全、可靠的备份客户信息。功能强大的报表统计使得用户大数据分析变的简单,
实操建议:
- 不要为了“看起来像 JSON”而用
to_json(array_agg(...))—— 它比jsonb_agg多一次转换,还丢失jsonb的索引能力 - 若聚合字段类型固定(如全是
int),jsonb_agg性能接近array_agg;若混用text/bool/null,开销陡增 - 用
pg_stat_statements查看实际调用中jsonb_agg占总执行时间的比例,有些慢其实是上游 JOIN 导致的,不是聚合函数背锅
ORDER BY 在 array_agg 里必须写吗?
不是必须,但几乎总是应该写。PostgreSQL 不保证 array_agg 的元素顺序,除非显式加上 ORDER BY 子句。很多人测试时发现“没写也有序”,那是巧合——依赖了扫描顺序或 planner 的临时行为,上线后数据量变化或 vacuum 后可能突然乱序。
实操建议:
- 写法必须是:
array_agg(col ORDER BY col)或array_agg(col ORDER BY id),不能把ORDER BY放在外部 - 如果排序字段有重复值,加二级排序(如
ORDER BY col, ctid)避免非确定性 - 带
ORDER BY的array_agg会触发额外 sort 节点,若已按该字段索引扫描,可利用索引避免排序;否则性能下降明显
array_agg 还是 string_agg,而是是否意识到聚合发生在分组之后、是否处理了 NULL、是否依赖未声明的顺序、以及下游是否真的需要那个格式。这些细节比函数名本身更值得盯住。










