索引最大行大小错误


12

array列有上限吗?

插入数组字段时出现此错误-

PG::Error: ERROR:  index row size 3480 exceeds maximum 2712 for index "ix_data"

这是我的表格定义-

create table test_array(id varchar(50), data text[]);

ALTER TABLE test_array ADD PRIMARY KEY (id);

CREATE INDEX ix_data ON test_array USING GIN (data);

我需要在数组字段上建立索引,因为我正在对其进行一些查询。


可能data包含其中的标签列表,如Scott Snyder在此相关博客文章中所展示的那样吗?如果是这样,我可能会为您提供更好的解决方案。
Erwin Brandstetter,2012年

user310525,我想赞同Erwin的建议,如果您愿意在dba.se上创建一个帐户并标记一个主持人进行迁移,这会更好。
杰克说尝试topanswers.xyz 2012年

Answers:


14

问题

这是在pgsql.general上讨论非常相似的情况。这是关于b树索引中的限制的,但是都是一样的,因为GIN索引在内部使用b树索引作为,因此遇到了相同的大小限制(而不是普通b树中的项目大小)指数)。

我引用有关GIN索引实现手册

在内部,GIN索引包含基于键构建的B树索引,其中每个键是一个或多个索引项的元素

无论哪种方式,至少一个数组元素在列data太大而被索引。如果这仅仅是一个奇异的怪异值或某种意外,您可能可以截断该值并使用它来完成。

为了以下演示的目的,我将另外假设:数组中有很多长文本值。

简单的解决方案

您可以data根据哈希值替换数组中的元素。并通过相同的哈希函数发送查找值。当然,您可能希望将原件另外存储在某个地方。这样,我们几乎达到了我的第二个变种...

先进的解决方案

您可以为具有serial列的代理主键(实际上是一种基本的哈希值)的数组元素创建查找表-如果所涉及的元素值不是唯一的,则将更有趣:

CREATE TABLE elem (
  elem_id serial NOT NULL PRIMARY KEY
, elem    text UNIQUE NOT NULL
);

因为我们要查找elem,所以我们添加了一个索引- 但这一次是在表达式上添加一个索引,只有长文本的前10个字符。在大多数情况下,将搜索范围缩小到一个或几个匹配就足够了。根据您的数据分布调整大小。或使用更复杂的哈希函数。

CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));

这样您的列data将为类型int[]。我将表重命名为,data并摆脱了varchar(50)示例中的不祥之处:

CREATE TEMP TABLE data(
  data_id serial PRIMARY KEY
, data int[]
);

中的每个数组元素都data引用一个elem.elem_id。此时,您可以考虑将数组列替换为n:m表,从而规范您的架构并允许Postgres强制执行参照完整性。索引编制和常规处理变得更加容易...

但是,出于性能原因,int[]与GIN索引结合使用的色谱柱可能更好。存储空间小得多。在这种情况下,我们需要GIN索引:

CREATE INDEX data_data_gin_idx ON data USING GIN (data);

现在,GIN索引的每个(=数组元素)都是integerlong而不是long text。该指数将通过几个数量级较小,搜索将因此快。

缺点:在实际执行搜索之前,您必须elem_id先从表中查找elem。使用我新引入的功能索引elem_elem_left10_idx,它也将更快。

您可以在一个简单的查询中完成所有操作

SELECT d.*, e.*
FROM   elem e
JOIN   data d ON ARRAY[e.elem_id] <@ d.data
WHERE  left(e.elem, 10) = left('word1234word', 10) -- match index condition
AND    e.elem = 'word1234word';  -- need to recheck, functional index is lossy

您可能对扩展感兴趣,该扩展intarray提供了更多的运算符和运算符类。

sqlfiddle上的全功能实时演示。


2

错误与索引有关ix_data,而不与text[]字段有关。该特定索引类型中的行的最大大小限制为2712字节。如果您删除索引并再次尝试插入,它将为您工作。如果需要索引更大的字段,则可能需要研究postgres的全文本索引功能。


2

我在PostGIS地理专栏上找到了这个。这是因为我不小心创建了错误的索引。创建此类索引时,应包括USING GIST参数。


谢谢-就是这样!哇,到现在为止。可能节省了我几个小时。特别是因为我认为默认情况下使用GiST,但是我弄错了,它尝试使用b树。
乔纳斯(Jonas)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.