问题
这是在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索引的每个键(=数组元素)都是integer
long而不是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
提供了更多的运算符和运算符类。
data
包含其中的标签列表,如Scott Snyder在此相关博客文章中所展示的那样吗?如果是这样,我可能会为您提供更好的解决方案。