我有一个pl / pgsql脚本需要检查一个单词/句子是否在一个字符串中,它必须处理单词边界,并且不区分大小写。
示例:
所以显而易见的解决方案是使用正则表达式,如下所示:
select _label ~* (E'\\y' || _pattern || E'\\y') into _match;
与简单的
相比,它有效,但速度很慢select _label ilike '%' || _pattern || '%' into _match;
这包含在我的脚本调用A LOT的函数中(数以千万计,我做了大量的递归),并且根据这个要求,整个运行时间翻了一倍。
现在我的问题是,有更快的方法来实现这个吗?
感谢。
编辑:最终使用了这个:
if _label ilike '%' || _pattern || '%' then
select _label ~* (E'\\m' || _pattern || E'\\M') into _match;
end if;
它明显更快。
答案 0 :(得分:2)
我会考虑full text search功能,但根据您的描述,我可能会使用PostgreSQL arrays实现此功能。
首先:定义一个带标签的函数,将它缩小(或者如果你愿意的话大写),在字边界上拆分它,然后返回一个数组。说:
CREATE OR REPLACE FUNCTION label_to_array(text) RETURNS text[] AS $$
SELECT regexp_split_to_array(lower($1), E'\\W');
$$ LANGUAGE sql IMMUTABLE;
$ select label_to_array('my label xx zz yy');
label_to_array
---------------------
{my,label,xx,zz,yy}
现在,在此功能上创建GIN index:
CREATE INDEX sometable_label_array_key ON sometable
USING GIN((label_to_array(label));
从这里开始,PostgreSQL可以将此索引用于涉及array operators的许多查询,例如“contains”:
SELECT *
FROM sometable
WHERE label_to_array(label) @> label_to_array('my label');
此查询会将'my label'
拆分为{my,label}
,然后使用索引查找包含my
的行列表,并将其与包含label
的行列表相交},然后返回结果。这并不完全等同于您的原始查询(因为它不检查它们的顺序),但由于它使用索引来消除表中的大多数行,因此在末尾添加原始检查可以正常工作:< / p>
SELECT *
FROM sometable
WHERE label_to_array(label) <@ label_to_array('my label')
AND label ~* (E'\\y' || 'my label' || E'\\y');