如何在非常大的 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
投票

count(*)的子查询中使用UPDATE
作为简单的
聚合函数
,然后加入
names
.

假设新列已经存在:

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

您不需要此操作的任何索引,顺序扫描即可。稍后创建索引是对的。 (不过,如果

(names)
上的索引存在,它可能会被使用。)

实际上,如果你可以自由地这样做,那么只创建一个新表可能更便宜。因为在 Postgres 中更新意味着编写一个新的行版本,这很昂贵,尤其是在更新 big 表的每一行时。参见:

假设新列还不存在:

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()
作为窗口函数,它不聚合行,而是保留每个输入行。

当然,整个操作几乎没有意义,如果你以后要添加更多行,并且每次都必须重新计算和更新。在这种情况下,我会 not 根本不添加此列。在

(names)
上有一个索引,并在运行中或在 viewmaterialized view 中进行计数。

如果

names
是一个长字符串,考虑在
(hashtextextended(names))
上使用更小的表达式索引。参见:

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

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