将非常宽的(超过1600列)查询导出到CSV

时间:2015-09-03 14:24:02

标签: java postgresql

在我目前的项目中,我们在postgres数据库中存储了许多小型表。最常见的操作是导出CSV文件,该文件是从公共密钥上连接的一些/所有表中选择的列。每列可以是任何数据类型,因为它由用户输入系统的内容决定。

我通过创建一个X列宽的表来实现结果,然后将数据复制到其中,其中X是用户选择的列数。

我的问题是用户经常想要导出数千列。我很快就达到了postgres允许我创建的最大表格,即1600.根据我的理解,这受到页面大小,列数/每列内存大小的限制。我可以增加页面大小,但我最终会继续达到这个限制。

我的新解决方案是在多个表中中断导出,其中每个表都写入其自己的csv文件。键列将位于所有文件中,因此其他一些程序可能会索引和链接数据。

我的问题是,如何确定每列占用多少空间?每种数据类型是否占用线性内存量?我需要考虑填充吗?

1 个答案:

答案 0 :(得分:0)

除了1664列之外,您甚至不能\copy (SELECT ...)行:

ERROR: target lists can have at most 1664 entries

所以你必须找到一种不同的方法来做到这一点。

增加PostgreSQL的页面大小可以解决问题,但不会解决您的问题,只是延迟它,并在此过程中创建许多其他问题。非默认块大小未经过大量测试,可能无法正常执行,并且在执行PITR /备份和还原/ pg_upgrade等时非常痛苦。

考虑使用Talend Studio,Pentaho Kettle或CloverETL等ETL工具来处理导出并加入数据。

  

我的问题是,如何确定每列占用多少空间?

使用pg_column_size。请注意,根据TOAST documentation,某些类型可以按压缩和脱节存储,因此pg_column_size(somecol)pg_column_size('text_of_somecol') 不是同一件事。此外,pg_column_size不报告托管指针的宽度,以便在线外存储TOAST-able类型,它会报告存储的大小。因此,对于TOASTable(可变长度)类型,您必须根据记录的大小自行处理:

  

允许varlena头字节,TOAST指针数据的总大小因此是18个字节,而不管所表示的值的实际大小。

基元类型是简单的固定宽度类型。 float4,float8,int4,int8,bool,"char"charcharacter不一样,引号很重要)等。

存储文本或类文本数据的任何内容都是可变宽度。 textvarcharbytea等都是非常好的。

您可以通过查询pg_type目录来了解具体信息。有关字段的含义,请参阅文档。

  

每种数据类型是否占用线性内存量?

如上所述,这取决于类型。

  

我需要考虑填充吗?

是。它的类型特定并且与存储器对齐要求有关。有关对齐信息,请参阅pg_type目录。

整行上的

pg_column_size,例如select pg_column_size(x) FROM mytable可以提供信息。

有关gorey的详细信息,请参阅src/backend/access/common/heaptuple.c上的评论。