postgresql 如何将对多个表行的查询转换为使用单个数组?

ivqmmu1c  于 2022-12-23  发布在  PostgreSQL
关注(0)|答案(1)|浏览(311)

我以前有这个表:

CREATE TABLE traces_v0
 ( canvas_id UUID NOT NULL
 , tlid BIGINT NOT NULL
 , trace_id UUID NOT NULL
 , timestamp TIMESTAMP WITH TIME ZONE NOT NULL
 , PRIMARY KEY (canvas_id, tlid, trace_id)
 );

我想把它改成这个表格

CREATE TABLE traces_v0
 ( canvas_id UUID NOT NULL
 , root_tlid BIGINT NOT NULL
 , trace_id UUID NOT NULL
 , callgraph_tlids BIGINT[] NOT NULL
 , timestamp TIMESTAMP WITH TIME ZONE NOT NULL
 , PRIMARY KEY (canvas_id, root_tlid, trace_id)
 );

也就是说,以前每个(tlid, trace_id)有一行,现在有一行trace_id和一个callgraph_tlids数组。
我有一个在旧表上运行良好的查询:

SELECT tlid, trace_id
  FROM (
    SELECT
      tlid, trace_id,
      ROW_NUMBER() OVER (PARTITION BY tlid ORDER BY timestamp DESC) as row_num
    FROM traces_v0
    WHERE tlid = ANY(@tlids::bigint[])
      AND canvas_id = @canvasID
  ) t
  WHERE row_num <= 10

这将为每个tlids(一个bigint数组)获取最后10个按时间戳排序的(tlid, trace_id),这正是我所需要的,而且非常有效。
(fyi:“at”(@tlids)语法只是编写$1的一种奇特方式,我的postgres驱动程序支持这种语法)
我很难把它移植到新的表格布局中,我想出了下面的方法,除了它没有限制每个tlid按时间戳排序10个之外,其他都很有效:

SELECT callgraph_tlids, trace_id
FROM traces_v0
WHERE @tlids && callgraph_tlids  -- '&&' is the array overlap operator
  AND canvas_id = @canvasID
ORDER BY timestamp DESC"

如果将结果限制为每个tlid 10行,并按时间戳排序,那么如何执行此查询?
我用的是Postgres 9.6,如果有问题的话。

2o7dmzc5

2o7dmzc51#

如果我将结果限制为每个tlid 10行,并按时间戳排序,我该如何执行这个查询?

    • 如果**在旧设计中被聚集到新设计中的相同阵列中的所有行的时间戳一直是相同的,则用于新设计的该查询在逻辑上是等效的:
SELECT trace_id, tlid
FROM  (
   SELECT t.trace_id, c.tlid
        , row_number() OVER (PARTITION BY c.tlid ORDER BY t.timestamp DESC) AS rn
   FROM   traces_v0 t
   JOIN   LATERAL unnest(t.callgraph_tlids) c(tlid) ON c.tlid = ANY(@tlids)
   WHERE  t.canvas_id = @canvasid
   AND    t.callgraph_tlids && @tlids
   ) sub
WHERE  rn <= 10;

但这意味着ORDER BY timestamp DESC一直是一个不确定的排序顺序,您的新查询和旧查询一样不可靠。前10个可能会随着查询调用的不同而变化。如果您想要确定的结果,请向ORDER BY列表添加更多表达式作为决胜器,直到排序顺序明确为止-可能在任何情况下都是如此。
联接条件ON c.tlid = ANY(@tlids)之上的WHERE条件t.callgraph_tlids && @tlids在逻辑上是冗余的,但通常有助于提高查询速度,尤其是在callgraph_tlids上使用GIN索引时。请参阅:

关于LATERAL联接:

  • 在PostgreSQL中,横向连接和子查询有什么区别?

甚至可以在你过时的,不支持的postgres 9. 6中工作。但是无论如何upgrade to a current version

    • 如果**聚合行的时间戳不同,则答案为:"你不能"

新设计删除了必需的信息。旧设计对每个tlid都有单独的时间戳,而新设计对整个阵列(callgraph_tlids)只有一个时间戳。

相关问题