如何在非常大的 Postgres 数据库中计算不同的值并将它们有效地保存到表中?

问题描述 投票:0回答:1

我对 Postgres 的经验几乎为零,我的电脑是 2010 年的。所以不是最快的,但仍然很强大。

我查看了推荐的答案,但我(还)没有得到它们 - 我想了解我在做什么。

我有一个 Postgres 数据库,其中包含

names
number_of_occurrences
列(加上一些其他每个名称都有唯一值的列)。数据库有大约3亿行(将增加到大约60亿行),大多数名称只出现一次,而有些可能出现数千甚至数百万次。

到目前为止,数据库只包含名称,现在我的工作是填写

number_of_occurrences
列。

最有效的方法是什么?

通常,我想我应该先在

DISTINCT
上使用
names
然后对每个不同的值运行计数,然后将其保存到新表中,最后丢弃旧表。

但是,这是不可能的,因为表中的每一行还有其他唯一值,因此必须将计数放回原始表中。

我实际上是想帮助我妻子解决工作中的问题。她研究的 X 染色体长约 1.4 亿个“字母”。问题是要找到满足某些特性(例如 GC 含量、Tm 等)、彼此相距一定距离(例如 100-150 个字母)并且在X 染色体,但不会出现在 Y 染色体上(理想情况下也不会出现在任何其他染色体上)。

第一步是创建引物(所有 1.4 亿 - X 染色体的 20,因为引物来自位置 1-20、2-21、3-22 等)并计算稍后所需的相关值(例如GC 含量,具有生物学背景的任何人的 Tm)。

表的主键是 id,一个自动生成的 UUID(所有其他表都相同)。

还没有创建索引——据我所知,在添加行的同时保持索引更新是昂贵的,而且创建完整的表然后索引它要快得多。

Schema 和其他表与问题无关,只会让头脑混乱。

我认为

number_of_occurrences
应该在创建表之后完成,但是有了使
number_of_occurrences
成为外键的想法,我实际上可以在每次添加行时设置或增加值,所以问题就消失了。

postgresql count distinct
1个回答
0
投票

UPDATE
的子查询中使用普通聚合并返回
names

假设新列已经存在:

UPDATE tbl t
SET    number_of_occurrences = ct.ct
FROM  (
   SELECT names, count(*) AS ct
   FROM   tbl
   GROUP  BY 1
   ) ct
WHERE  t.names = ct.names;

此操作不需要任何索引,因为无论如何都会读取和更新所有行。你以后创建索引是对的。

实际上,如果你可以自由地这样做,那么只创建一个新表可能更便宜。假设新列还不存在:

CREATE TABLE tl2 AS 
SELECT *, count(*) OVER (PARTITION BY name) AS number_of_occurrences
FROM   tbl
ORDER  BY names;  -- optional, but possibly beneficial.

DROP TABLE tbl;

这次使用

count()
作为窗口函数,它不聚合行,而是保留每个输入行。

旁白:“名字”是一个狡猾的名字。

© www.soinside.com 2019 - 2024. All rights reserved.