索引最大行大小错误

15 postgresql performance index database-design postgresql-9.1

array列有上限吗?

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

PG::Error: ERROR:  index row size 3480 exceeds maximum 2712 for index "ix_data"
Run Code Online (Sandbox Code Playgroud)

这是我的表定义 -

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);
Run Code Online (Sandbox Code Playgroud)

我需要数组字段的索引,因为我正在对它进行一些查找。

Erw*_*ter 15

问题

这是在 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
);
Run Code Online (Sandbox Code Playgroud)

由于我们要查找elem,所以我们添加了一个索引——这次是一个表达式索引,只有长文本的前 10 个字符。在大多数情况下,这应该足以将搜索范围缩小到一个或几个点击。根据您的数据分布调整大小。或者使用更复杂的哈希函数。

CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
Run Code Online (Sandbox Code Playgroud)

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

CREATE TABLE data(
  data_id serial PRIMARY KEY
, data int[]
);
Run Code Online (Sandbox Code Playgroud)

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

但是,出于性能原因,int[]列与 GIN 索引组合可能会更好。存储大小为很多小。在这种情况下,我们需要 GIN 索引:

CREATE INDEX data_data_gin_idx ON data USING GIN (data);
Run Code Online (Sandbox Code Playgroud)

现在,GIN 索引(= 数组元素)的每个都是一个integer而不是 longish 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
Run Code Online (Sandbox Code Playgroud)

您可能对intarray提供额外运算符和运算符类的扩展感兴趣。

db<>fiddle here
旧的sqlfiddle


小智 6

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


jce*_*ern 2

错误出在索引上ix_data,而不是text[]字段上。该特定索引类型中的行的最大大小限制为2712字节。如果您删除索引并再次尝试插入,它应该对您有用。如果您需要索引更大的字段,您可能需要研究Postgres 的全文索引功能。