PostgreSQL hstore:使用索引提高LIKE性能?

时间:2013-10-24 11:40:54

标签: postgresql indexing sql-like hstore

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

查询:

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索引没有多大意义,因为列非常大而且不需要几何运算符(我可能错了)。

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

1 个答案:

答案 0 :(得分: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”都是“一般化的” - 它们的目的是多用途)。如果您查看the docs for the hstore module,您将看到hstore列上的gist或gin索引支持哪些运算符*。其中一个是“?”,它测试是否存在密钥。根据查找键(x,y,z)的稀疏性,您可以通过在列上定义gist或gin索引并添加额外条件(例如“where(hstore?'x'和hstore-> 'x'ilike'123%')“;假设没有多行有密钥x这应该给你一个不错的提升,否则如果密钥x几乎在每行中你将回到全表扫描。

当决定是否使用gist或gin时,如果你查看postgres文档并且在这里你可以找到一些指导原则,基本上杜松子酒往往更快查找但占用更多空间并且更慢构建和维护(意思是记住你是在写还是读更多数据) - 我不确定是否有针对hstore类型的具体建议。

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

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