使用'类似'在PostgreSQL中查询性能

时间:2012-11-01 18:59:23

标签: performance postgresql indexing

我需要从表中检索某些行,具体取决于特定列中的某些值,在示例中名为 columnX

select *
from tableName 
where columnX similar to ('%A%|%B%|%C%|%1%|%2%|%3%')

因此,如果 columnX 包含至少一个指定的值(A,B,C,1,2,3),我将保留该行。

我找不到比使用类似更好的方法。问题是对于行数超过一百万的表,查询花费的时间太长。

我试过索引它:

create index tableName_columnX_idx on tableName (columnX) 
where columnX similar to ('%A%|%B%|%C%|%1%|%2%|%3%')

但是,如果条件是可变的(值可能不是A,B,C,1,2,3),我需要为每个条件使用不同的索引。

这个问题有更好的解决方案吗?

编辑:感谢大家的反馈。看起来我已经达到了这一点,可能是因为设计错误(我在separated question发布的主题)。

4 个答案:

答案 0 :(得分:3)

如果您只想搜索单字符值的列表,则将每个字符串拆分为一个字符数组并索引该数组:

CREATE INDEX
        ix_tablename_columnxlist
ON      tableName
USING   GIN((REGEXP_SPLIT_TO_ARRAY(columnX, '')))

然后搜索索引:

SELECT  *
FROM    tableName
WHERE   REGEXP_SPLIT_TO_ARRAY(columnX, '') && ARRAY['A', 'B', 'C', '1', '2', '3']

答案 1 :(得分:1)

我会将此作为答案发布,因为它可能在将来指导其他人:为什么不有6列,haveAhaveBhave3并执行6部分OR查询?或者使用位掩码?

如果每个属性分配的属性太多,我可能会尝试创建一个“属性”表:

(fkey, attr) VALUES (1, 'A'), (1, 'B'), (2, '3')

让DBMS担心优化问题。

答案 2 :(得分:1)

我同意@Quassnoi,GIN index是最快最简单的 - 除非写入性能或磁盘空间是问题,因为它占用了大量空间并且为INSERT吃了相当多的性能,{ {1}}和UPDATE

我的补充答案由你的陈述引发:

DELETE

如果这是你找到的,那么你的搜索还没有结束。 I can't find a better approach than using similar to. 完全浪费时间。从字面上看。 PostgreSQL只是为了符合(奇怪的)SQL标准。检查SIMILAR TO的输出以查找您的查询,您会发现EXPLAIN ANALYZE已被正则表达式替换。

在内部,每个SIMILAR TO表达式都被重写为正则表达式。因此,对于每个SIMILAR TO表达式,至少有一个正则表达式匹配更快一些。如果您不确定,请SIMILAR TO为您翻译。你不会在手册中找到这个,PostgreSQL不承诺这样做,但我还没有看到异常。

related answer on dba.SE中的详细信息。

答案 3 :(得分:1)

这让我觉得这是一个数据建模问题。您似乎使用text字段作为集合,存储单个字符代码以标识集合中存在的值。

如果是这样,我想重新构建此表以使用以下方法之一:

  • 标准关系规范化。删除columnX,并将其替换为新表,其中包含对tableName(id)的外键引用和charcode列,其中包含每行旧columnX中的一个字符,例如{ {1}}。然后,您可以使用普通的SQL子查询,连接等在CREATE TABLE tablename_columnx_set(tablename_id integer not null references tablename(id), charcode "char", primary key (tablename_id, charcode))中相当有效地搜索密钥。如果您的应用程序无法应对该更改,您可以始终保留columnX并使用触发器维护边表。

  • 使用虚拟值将columnX转换为columnX个键。然后,您可以使用hstore之类的hstore运算符。 columnX ?| ARRAY['A','B','C']的hstore上的GiST索引应该为这些操作提供相当可靠的性能。

  • 如果您的表格更改率较低且您可以支付GIN索引的费用,则拆分为数组as recommended by Quassnoi;

  • columnX转换为整数数组,使用columnX和intarray GiST索引。有一个代码映射表到整数或在应用程序中转换。

时间允许我会跟进每个人的演示。弥补虚拟数据是一件痛苦的事情,因此它将取决于其他方面的情况。