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
提供额外运算符和运算符类的扩展感兴趣。