3

我需要根据特定列中的某些值从表中检索某些行,在示例中名为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),我需要为每个条件使用不同的索引。

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

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

4

4 回答 4

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']
于 2012-11-01T19:13:43.443 回答
1

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

如果是这样,我想改造此表以使用以下方法之一:

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

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

  • 如果您的表更改率较低并且您可以支付 GIN 索引的成本,请按照Quassnoi 的建议拆分为数组;

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

如果时间允许,我会跟进每个演示。制作虚拟数据是一件很痛苦的事情,所以这取决于其他情况。

于 2012-11-02T00:14:39.450 回答
1

我同意@Quassnoi 的观点,GIN 索引是最快和最简单的——除非写入性能或磁盘空间是问题,因为它占用了大量空间并且占用了INSERT,UPDATEDELETE.

我的附加答案是由您的陈述触发的:

I can't find a better approach than using similar to.

如果这是您找到的,那么您的搜索还没有结束。SIMILAR TO完全是浪费时间。字面上地。PostgreSQL 仅以符合(奇怪的)SQL 标准为特征。检查EXPLAIN ANALYZE查询的输出,您会发现它SIMILAR TO已被正则表达式替换。

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

有关 dba.SE的相关答案中的更多详细信息。

于 2012-11-02T00:12:17.213 回答
1

我会将此作为答案发布,因为它可能会在未来指导其他人:为什么不使用 6 列haveA、、haveB~have3并执行 6 部分OR查询?还是使用位掩码?

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

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

并让 DBMS 担心优化。

于 2012-11-01T19:07:14.430 回答