繁体   English   中英

Postgres jsonb 数组连接

[英]Postgres jsonb array join

我在表格中有一个 jsonb 文档。 该文档在文档中有一个 cameraIds 数组。 我正在尝试将此数据与作为普通表的cameras表连接,其中cameraId是一列,并从带有jsonb列的表中返回唯一行(为什么我在查询中使用group by)。

任何有关如何优化此查询以提高性能的建议将不胜感激。

JSONB 列示例:

{
  "date": {
    "end": "2018-11-02T22:00:00.000Z", 
    "start": "2018-11-02T14:30:00.000Z"
  }, 
  "cameraIds": [100, 101], 
  "networkId": 5, 
  "filters": [], 
  "includeUnprocessed": true, 
  "reason": "some reason", 
  "vehicleFilter": { 
    "bodyInfo": "something", 
    "lpInfo": "something"
  }
}

询问:

select ssr.id,
                a.name                                               as user_name,
                ssr.start_date,
                ssr.end_date,
                ssr.created_at,
                ssr.payload -> 'filters'                       as pretty_filters,
                ssr.payload -> 'reason'                              as reason,
                ssr.payload -> 'includePlates'                as include_plates,
                ssr.payload -> 'vehicleFilter' -> 'bodyInfo'         as vbf,
                ssr.payload -> 'vehicleFilter' -> 'lpInfo' as lpInfo,
                array_agg(n.name) filter (where n.organization_id = ${orgId})  as network_names,
                array_agg(c.name) filter (where n.organization_id = ${orgId})  as camera_names
from
    ssr
    cross join jsonb_array_elements(ssr.payload -> 'cameraIds') camera_id
         inner join cameras as c on c.id = camera_id::int
         inner join networks as n on n.id = c.network_id
         inner join accounts as a on ssr.account_id = a.id
where n.organization_id = ${someId}
and ssr.created_at between ${startDate} and ${endDat}
group by 1,2,3,4,5,6,7,8,9,10
order BY ssr.created_at desc
    OFFSET 0
LIMIT 25;

您的查询说:

where n.organization_id = ${someId}

但随后聚合FILTER说:

where n.organization_id = ${orgId}

......这是一个矛盾。 聚合的 arrays 将始终为空 - 除非${orgId}恰好与${someId}相同,但FILTER子句是无用的噪音。 IOW,该查询似乎没有任何意义。

删除聚合FILTER子句后查询可能有意义:

SELECT s.id
     , a.name                                      AS user_name
     , s.start_date
     , s.end_date
     , s.created_at
     , s.payload ->> 'filters'                     AS pretty_filters
     , s.payload ->> 'reason'                      AS reason
     , s.payload ->> 'includePlates'               AS include_plates
     , s.payload -> 'vehicleFilter' ->> 'bodyInfo' AS vbf
     , s.payload -> 'vehicleFilter' ->> 'lpInfo'   AS lpInfo
     , cn.camera_names
     , cn.network_names
FROM   ssr      s
JOIN   accounts a ON a.id = s.account_id  -- assuming referential integrity
CROSS  JOIN LATERAL (
   SELECT array_agg(c.name) AS camera_names   -- sort order?
        , array_agg(n.name) AS network_names  -- same order? distinct?
   FROM   jsonb_array_elements_text(ssr.payload -> 'cameraIds') i(camera_id)
   JOIN   cameras  c ON c.id = i.camera_id::int
   JOIN   networks n ON n.id = c.network_id
   WHERE  n.organization_id = ${orgId}
   ) cn
WHERE  s.created_at BETWEEN ${startDate} AND ${endDate}  -- ?
ORDER  BY s.created_at DESC NULLS LAST
LIMIT  25;

关键是LATERAL子查询,它避免了ssr中的行重复,因此我们也可以删除外部GROUP BY 应该会快很多。

另请注意->>而不是->jsonb_array_elements_text() 看:

我在查询中更可疑的地方留下了一些问号。 值得注意的是, BETWEEN几乎总是错误的时间戳工具。 看:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM