Postgresql Postgres分区?

Postgresql Postgres分区?,postgresql,database-partitioning,Postgresql,Database Partitioning,我的软件每30分钟运行一次cronjob,它从谷歌分析/社交网络中提取数据,并将结果插入Postgres数据库 数据如下所示: url text NOT NULL, rangeStart timestamp NOT NULL, rangeEnd timestamp NOT NULL, createdAt timestamp DEFAULT now() NOT NULL, ... (various integer columns) 因为一个查询返回10000多个项目,所以将这些数据存储在

我的软件每30分钟运行一次cronjob,它从谷歌分析/社交网络中提取数据,并将结果插入Postgres数据库

数据如下所示:

url text NOT NULL,    
rangeStart timestamp NOT NULL,
rangeEnd timestamp NOT NULL,
createdAt timestamp DEFAULT now() NOT NULL,
...
(various integer columns)
因为一个查询返回10000多个项目,所以将这些数据存储在一个表中显然不是一个好主意。按照这个速度,cronjob将每天生成约48万条记录,每月生成约1450万条记录

我认为解决方案应该使用几个表,例如,我可以使用一个特定的表来存储给定月份生成的数据:stats_2015_09、stats_2015_10、stats_2015_11等等

我知道Postgres支持表分区。然而,我对这个概念还不熟悉,所以我不确定什么是最好的方法。在这种情况下,我需要分区,还是应该手动创建这些表?或者有更好的解决办法

稍后将以各种方式查询数据,这些查询将运行得很快

编辑:


如果我最终得到12-14个表,每个表存储1000-2000万行,Postgres应该仍然能够快速运行select语句,对吗?插入不必非常快。

对于注释来说,这太长了

在各种情况下,分区是一个好主意。我想到的两个问题是:

  • 您的查询有一个
    WHERE
    子句,可以很容易地映射到一个或几个分区上
  • 您需要一种快速删除历史数据的方法(删除分区比删除记录快)
如果不知道要运行的查询类型,就很难说分区是否是个好主意

我想我可以说,将数据拆分成不同的表是一个坏主意,因为这是一个维护噩梦:

  • 表中不能有外键引用
  • 跨越多个表的查询很麻烦,因此很难回答简单的问题
  • 维护表变成了一场噩梦(添加/删除列)
  • 如果用户具有不同的角色,则必须仔细维护权限

在任何情况下,都应该从Postgres关于分区的文档开始,这就是。我应该注意到,Postgres的实现比其他数据库中的实现要困难一些,因此您可能需要查看MySQL或SQL Server的文档,了解它在做什么。

首先,我想质疑您问题的前提:

因为一个查询返回10000多个项目,所以将这些数据存储在一个表中显然不是一个好主意

据我所知,没有根本原因说明数据库不能很好地处理一个包含数百万行的表。在极端情况下,如果您创建了一个没有索引的表,并且只是在表中添加行,则Postgres可以继续将这些行写入磁盘,直到存储空间用完为止。(我不确定内部可能还有其他限制;但如果是这样的话,那就太大了。)

只有当你试图用这些数据做一些事情时,问题才会出现,而确切的问题——因此也就是确切的解决方案——取决于你做了什么

如果要定期删除在固定时间之前插入的所有行,可以对
createdAt
列上的数据进行分区。然后,
DELETE
将成为一个非常有效的
DROP TABLE
,所有的
INSERT
都将通过触发器路由到“当前”分区(如果导入脚本知道分区命名方案,甚至可以绕过它)<但是,code>SELECTs可能无法在其
WHERE
子句中指定
createAt
值的范围,因此需要查询所有分区并合并结果。一次保留的分区越多,效率就越低

或者,您可以检查表上的工作负载,并查看所有查询是否已经显式地声明了
rangeStart
值。在这种情况下,您可以在
rangeStart
上进行分区,并且在规划每个
SELECT
查询时,查询规划器将能够消除除一个或几个分区以外的所有分区<代码>插入s需要通过触发器路由到相应的表,而维护操作(例如删除不再需要的旧数据)的效率要低得多

或者,您可能知道,一旦
rangeEnd
变得“太旧”,您将不再需要数据,并且可以获得两个好处:按
rangeEnd
分区,确保所有
SELECT
查询明确提及
rangeEnd
,并删除包含您不再感兴趣的数据的分区

借用git中Linus Torvald的术语,分区的“管道”是以表继承的形式构建到Postgres中的,但是除了手册中的示例之外,在“瓷器”方面几乎没有其他内容。然而,有一个非常好的方法,它提供了基于ID或日期范围管理分区集的功能;通过阅读文档了解不同的操作模式非常值得。在我的例子中,没有一个是完全匹配的,但是分叉扩展要比从头开始编写所有东西容易得多

请记住,分区并不是免费的,如果基于上述考虑因素,没有明显的候选列进行分区,那么实际上最好将数据保留在一个表中,并考虑其他优化策略。例如,部分索引(
创建索引…其中
)可能能够处理最常查询的行子集;可能与“覆盖索引”相结合,Postgres可以直接从索引返回查询结果,而无需参考主表结构(“仅索引扫描”)。

关于这个主题的内容很简洁,应该足够了。另请参见