Performance 使用';类似于';
我需要根据特定列中的特定值从表中检索特定行,该列在示例中命名为columnX:Performance 使用';类似于';,performance,postgresql,indexing,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_id
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),我需要为每个条件使用不同的索引
这个问题有没有更好的解决办法
编辑:谢谢大家的反馈。看来我达到这一点可能是因为一个设计错误(我在a中发布的主题)。我将发布这篇文章作为一个答案,因为它可能会在将来指导其他人:为什么不有6个栏,
haveA
,haveB
~have3
和做一个6部分的或
查询?还是使用位掩码
如果属性太多,无法为每个属性分配一列,我可能会尝试创建一个“属性”表:
让DBMS来考虑优化问题。如果只搜索一个字符值的列表,则将每个字符串拆分为一个字符数组,并为数组编制索引:
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']
我同意@Quassnoi,a是最快和最简单的-除非写入性能或磁盘空间是问题,因为它占用了大量空间,并消耗了插入
、更新
和删除
的大量性能
我的补充回答是由你的陈述引发的:
I can't find a better approach than using similar to.
如果这就是你发现的,那么你的搜索还没有结束<代码>类似于完全是浪费时间。字面上PostgreSQL的特点是符合(奇怪的)SQL标准。检查查询的EXPLAIN ANALYZE
输出,您会发现类似于的已被正则表达式替换
在内部,每个类似于
表达式的都被重写为正则表达式。因此,对于每个类似于
表达式的,至少有一个正则表达式匹配要快一点。如果您不确定,让解释分析为您翻译。您在手册中找不到这一点,PostgreSQL不承诺这样做,但我还没有看到例外
更多细节。这是一个数据建模问题。您似乎将文本
字段用作一个集合,存储单字符代码以识别集合中存在的值
如果是这样,我希望使用以下方法之一重新构建此表:
- 标准关系规范化。删除
columnX
,并将其替换为一个新表,该表具有对tableName(id)
的外键引用,以及一个charcode
列,该列每行包含一个来自旧columnX
的字符,如CREATE table tableName\u columnX\u set(tableName\u id integer非空引用tableName(id),charcode“char”,主键(tablename\u id,charcode))
。然后,您可以使用普通的SQL子查询、联接等相当有效地搜索columnX
中的键。如果您的应用程序无法处理该更改,您可以始终保留columnX
,并使用触发器维护边表
- 将
columnX
转换为具有伪值的键的hstore
。然后可以使用诸如columnX?| ARRAY['A','B','C']
之类的hstore运算符。columnX
的hstore上的GiST
索引应该为这些操作提供相当可靠的性能
- 如果您的表更改率较低,并且您可以支付GIN索引的费用,则拆分为一个数组
- 将
columnX
转换为整数数组,使用intarray
和intarray索引。在应用程序中具有代码到整数或转换的映射表
时间允许的话,我会跟进每一个的演示。生成虚拟数据是一件痛苦的事,因此它将取决于其他情况。您是否总是要搜索单个字符值?类似于'%ABC%|%BCD%'
的查询是否可能?是的,是基于单个字符的搜索。@FedericoCristina实际上,columnX
是由文本
字段中的单个字符代码表示的集合。对的这意味着列X中的值顺序无关紧要。谢谢您的回答。也许我应该更好地解释这些值(A,B,C,1,2,3),其中仅用于示例。整套选项大约有24种。@FedericoCristina:更新了我的答案。我不确定最后一点是否正确。如果columnX
具有值ZAB
并且您正在搜索A | B
,则该值不匹配,但应该匹配。哦,是的,抱歉。请将其归因于约40小时的失眠:)GIN索引维护起来可能非常昂贵,因此它并不特别适合插入/更新/删除率高的表。对于这个特殊的应用程序,这可能是问题,也可能不是问题。谢谢您的回答。不幸的是,这些表在不断变化(插入和更新)@FedericoCristina:不知道场景的详细信息,但是,在大多数情况下,频繁的完整扫描意味着服务器上的负载比索引更新(甚至GIN
)要大。你真的试过这两种方法吗?同样,如果你考虑重新设计并能够安装扩展,你可以将你的标志存储在原生代码> iTalay中,并用更友好的更新代码<代码> GIST<代码>。看起来你对建模问题是正确的。我应该在那里做一些重构。我已经编辑了我的问题,并引用了一个新的领域特定问题。谢谢链接!你说得对
I can't find a better approach than using similar to.