PostgreSQL:有效地将列表查询结果聚合到 JSON 对象中
PostgreSQL: Efficiently aggregate a list query result into JSON object
我需要 return 一个查询结果,在该查询中我匹配 table 中的一行,然后在 JSON 中聚合引用该行的最多 500,000 个文本值.
- JSON 必须是名称为数据点的地图。它需要是一个 key:value 对象,因为它会在我的 golang 后端被序列化为一个哈希映射,这将允许我在恒定时间内搜索它。我不在乎什么值是空字符串或 null 是首选,以减少传输和序列化时间。
最初我尝试使用 jsonb_build_object
但速度很慢。这是查询的简化版本:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
jsonb_build_object( -- the aggregate takes a very long time
SELECT
table_b.item
FROM
table_b
WHERE
table_a.id = table_b.table_a_id
)
FROM
table_a
WHERE
table_a.id = <some_id_input>;
我的下一步是获取一个数组,然后将其转换为 JSON。这证明效率更高:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
to_jsonb( ARRAY (
SELECT
table_b.item
FROM
table_b
WHERE
table_a.id = table_b.table_a_id
))
FROM
table_a
WHERE
table_a.id = <some_id_input>;
虽然效率更高,但当我需要 JSON 对象时,它会给我一个 JSON 数组...
PostgreSQL 14 中是否有一种简单有效的方法来生成我需要的内容?
加入聚合结果:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
b.items
FROM table_a
LEFT JOIN (
select table_a_id, jsonb_agg(table_b.item) as items
FROM table_b
GROUP by table_a_id
) b on b.table_a_id = table_a.id
WHERE
table_a.id = <some_id_input>;
或者在将其限制为单个 table_a.id
:
时使用横向连接
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
b.items
FROM table_a
LEFT JOIN LATERAL (
select jsonb_agg(table_b.item) as items
FROM table_b
WHERE table_b.table_a_id = table_a.id
) b on true
WHERE
table_a.id = <some_id_input>;
我不确定,但如果使用本机数组 (array_agg()
) 比 JSON 创建 500.000 个项目的数组更有效,我不会感到惊讶
我需要 return 一个查询结果,在该查询中我匹配 table 中的一行,然后在 JSON 中聚合引用该行的最多 500,000 个文本值.
- JSON 必须是名称为数据点的地图。它需要是一个 key:value 对象,因为它会在我的 golang 后端被序列化为一个哈希映射,这将允许我在恒定时间内搜索它。我不在乎什么值是空字符串或 null 是首选,以减少传输和序列化时间。
最初我尝试使用 jsonb_build_object
但速度很慢。这是查询的简化版本:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
jsonb_build_object( -- the aggregate takes a very long time
SELECT
table_b.item
FROM
table_b
WHERE
table_a.id = table_b.table_a_id
)
FROM
table_a
WHERE
table_a.id = <some_id_input>;
我的下一步是获取一个数组,然后将其转换为 JSON。这证明效率更高:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
to_jsonb( ARRAY (
SELECT
table_b.item
FROM
table_b
WHERE
table_a.id = table_b.table_a_id
))
FROM
table_a
WHERE
table_a.id = <some_id_input>;
虽然效率更高,但当我需要 JSON 对象时,它会给我一个 JSON 数组...
PostgreSQL 14 中是否有一种简单有效的方法来生成我需要的内容?
加入聚合结果:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
b.items
FROM table_a
LEFT JOIN (
select table_a_id, jsonb_agg(table_b.item) as items
FROM table_b
GROUP by table_a_id
) b on b.table_a_id = table_a.id
WHERE
table_a.id = <some_id_input>;
或者在将其限制为单个 table_a.id
:
SELECT
table_a.id,
table_a.name,
table_a.description,
table_a.created,
table_a.createdby,
table_a.modified,
table_a.modifiedby,
b.items
FROM table_a
LEFT JOIN LATERAL (
select jsonb_agg(table_b.item) as items
FROM table_b
WHERE table_b.table_a_id = table_a.id
) b on true
WHERE
table_a.id = <some_id_input>;
我不确定,但如果使用本机数组 (array_agg()
) 比 JSON 创建 500.000 个项目的数组更有效,我不会感到惊讶