1

我有大量具有不均匀属性的非规范化数据(有些属性存在,有些不存在)并将其插入到单个列中。此列包含大约 300 个键/值对,每行总大小为 5000 个字符。我想对其中一些属性进行字符串搜索查询,并在总共 100000 行上使用ilike和运算符。OR

查询:

SELECT hstore->'a' AS a, hstore->'b' AS b,hstore->'c' AS c
  FROM table
  WHERE
       hstore->'x' ILIKE '123%' 
    or hstore->'y' ILIKE '123%'
    or hstore->'z' ILIKE '123%'

通过对未索引表的此查询,我得到了超过 500 毫秒的运行时间(explain analyze)。

使用我的旧 RDBMS 索引表,其中每个属性都在一个列中,我实现了更好的性能,虽然不太灵活。

我在这些 hstore 属性上尝试了不同/多个索引,比如

CREATE INDEX idx_table_hstore ON table( (hstore->'a') )

每个索引一个,但性能与根本没有索引相同。

据我了解,GIN/GIST 索引没有多大意义,因为该列非常大并且不需要几何运算符(我可能错了)。

在这种情况下,您会使用什么索引方法来获得与使用经典模型相似甚至更好的性能?

4

1 回答 1

3

这在很大程度上取决于您的具体用例,这并不完全清楚。在您的示例查询中,您正在测试键 x、y 和 z 的值。如果这三个键(或所有键的一些相对较小的子集)是唯一用于查找的键,您可能会考虑将它们移动到它们自己的列中 - 那么您的查找字段是固定的,但您仍然具有 hstore 列的灵活性。

也不清楚您是在每个单独的键上创建索引还是仅在查找列上创建索引。如果你在每个键上都做了一个,你说的是大约 300 个索引(你提到有大约 300 个键),然后你也放弃了 hstore 的一些灵活性(必须创建这些索引之一对于每一个键)。我会在这里只使用查找列 (x, y, z) 并稍微调整它们看起来像这样:

create index idx_t_h_x on t ((lower(h->'x')));

您提到的索引不支持 ilike 运算符,因此您需要对值的较低(或较高)进行索引,然后修改谓词以匹配,如下所示:

SELECT hstore->'a' AS a, hstore->'b' AS b,hstore->'c' AS c
FROM table
WHERE lower(hstore->'x') LIKE '123%'

此外,gin/gist 索引不仅适用于几何运算(事实上,两个名称中的“g”都是“通用的”——它们旨在用于多用途)。如果您查看hstore 模块的文档,您将看到 hstore 列上的 gist 或 gin 索引支持哪些运算符*。其中之一是“?”,它测试是否存在密钥。根据查找键 (x, y, z) 的稀疏性,您可能会通过在列上定义 gist 或 gin 索引并添加额外条件(例如“where (hstore ? 'x' and hstore->' x' 我喜欢 '123%')"; 假设没有多少行有键 x 这应该会给您带来不错的提升,否则如果键 x 几乎在每一行中,您将返回全表扫描。

在决定是否使用 gist 或 gin 时,如果您查看 postgres 文档和此处的 SO,您会发现一些指导方针,基本上 gin 查找起来往往更快,但占用更多空间并且构建和维护速度较慢(意思是记住你是在写数据还是读数据更多)——我不确定是否有针对 hstore 类型的具体建议。

哦,而且,显然这一切都假设您的服务器已针对您的硬件和使用情况进行了适当的配置。正如我所指出的,您提供的索引不支持 ilike 运算符,因此永远不会使用。一旦你得到一个你认为应该使用的索引,你可能会尝试禁用表扫描(检查 enable_seqscan 的配置),看看你是否能找出规划器不使用它的原因。如果您的配置是开箱即用的,您可能将 random_page_cost 设置得很高,如果您的 work_mem 不够高,您可能会在磁盘上进行大量排序,等等。

*这里只是指出一个主题,并非所有索引类型都支持所有运算符。

于 2013-10-24T14:51:32.687 回答