LIKE和regex之间的PostgreSQL性能差异

LIKE和regex之间的PostgreSQL性能差异,sql,regex,postgresql,performance,sql-like,Sql,Regex,Postgresql,Performance,Sql Like,有人能解释一下这些SQL之间的巨大性能差异吗 SELECT count(*) as cnt FROM table WHERE name ~ '\*{3}'; -- Total runtime 12.000 - 18.000 ms SELECT count(*) as cnt FROM table WHERE name ~ '\*\*\*'; -- Total runtime 12.000 - 18.000 ms SELECT count(*) as cnt FROM table WHERE na

有人能解释一下这些SQL之间的巨大性能差异吗

SELECT count(*) as cnt FROM table WHERE name ~ '\*{3}'; -- Total runtime 12.000 - 18.000 ms
SELECT count(*) as cnt FROM table WHERE name ~ '\*\*\*'; -- Total runtime 12.000 - 18.000 ms
SELECT count(*) as cnt FROM table WHERE name LIKE '%***%'; -- Total runtime 5.000 - 7.000 ms
如您所见,LIKE运算符和简单正则表达式之间的差异是原来的两倍多(我认为LIKE运算符在内部会转换为正则表达式,应该没有任何差异)

那里几乎有13000行,“name”列是“text”类型。没有与表中定义的“名称”列相关的索引

编辑: 解释并分析其中的每一项:

EXPLAIN ANALYZE SELECT count(*) as cnt FROM datos WHERE nombre ~ '\*{3}';

Aggregate  (cost=894.32..894.33 rows=1 width=0) (actual time=18.279..18.280 rows=1 loops=1)
  ->  Seq Scan on datos (cost=0.00..894.31 rows=1 width=0) (actual time=0.620..18.266 rows=25 loops=1)
        Filter: (nombre ~ '\*{3}'::text)
Total runtime: 18.327 ms



我不确定我是否应该把它作为答案发表。。。我在PHP中做了一个类似的粗略比较——使用regex和简单strpos(作为LIKE的替代品)过滤巨大的数组。守则:

// regex filter
$filteredRegex = array_filter($a,function($item){
    return preg_match('/000/',$item);
});
// substring search filter
$filteredStrpos = array_filter($a,function($item){
    return strpos($item,'000')!==FALSE;
});
因此,对这段代码进行基准测试会导致正则表达式过滤器在时间上使strpos的结果加倍,因此我可以假设正则表达式的CPU成本大约是简单搜索子字符串的两倍


看起来@zerkms有所有的原因:)

类文本的
操作符(
~
)是由中的特定C代码实现的。它是完全独立于正则表达式的特殊代码。查看注释,它显然经过了特别优化,只实现了
%
\
作为通配符,并尽可能短接到出口,而正则表达式引擎要复杂几个数量级

请注意,在您的测试用例中,就像regexp与
like
相比是次优的一样,
like
strpos(名称,***')>0相比可能是次优的

strpos
是用实现的,它针对搜索文本中很少有部分匹配的大型子字符串进行了优化


在内部,这些函数都经过了合理的优化,但是当有多个方法达到相同的目标时,调用者的工作仍然是选择可能最好的方法。PostgreSQL不会为我们分析匹配的模式,并根据该分析将
regexp
转换为
LIKE
LIKE
转换为
strpos

Show
explain analyze
以获取reach请。@CraigRinger我在问题文本中添加了对每个查询的解释分析以运行正则表达式比较比应用类似于
格式的伪
更昂贵。@dmikam我不同意-正则表达式更难解析,也更难应用。如果您不同意我的意见,请尝试同时实现
LIKE
和PCRE兼容的引擎。然后比较哪一个花费更多的精力,工作更慢。“只匹配以***结尾的字符串”--不,那里也有空白。这三个查询占用空间很小,完全由内存/缓冲区提供。这就是CPU成本占总成本的主要原因。一旦必须从磁盘中提取数据,成本将主要由seektime和I/O决定,查询的性能大致相同。(至少:这是我所期望的)请注意,当模式包含文本字符串或以文本字符串开始时(作为预优化,以更快地失败),在使用Boyer-Moore算法启动引擎漫游之前,几个正则表达式引擎也会测试字符串。我不知道Postgres是否是这样。我像_match.c一样浏览了一遍,它肯定比正则表达式简单得多(即使它仍然是递归的)。所以我最初的错误是认为LIKE是使用regex或类似的东西在内部实现的。当然,strpos算法更“便宜”,但在我的粗略比较中,它证实了所选字符串分析算法的CPU成本可能会造成我的执行时间上的差异。这是SQL而不是PHP
EXPLAIN ANALYZE SELECT count(*) as cnt  FROM datos WHERE nombre LIKE '%***%';
Aggregate  (cost=894.32..894.33 rows=1 width=0) (actual time=4.258..4.258 rows=1 loops=1)
  ->  Seq Scan on datos  (cost=0.00..894.31 rows=1 width=0) (actual time=0.138..4.249 rows=25 loops=1)
        Filter: (nombre ~~ '%***%'::text)
Total runtime: 4.295 ms
// regex filter
$filteredRegex = array_filter($a,function($item){
    return preg_match('/000/',$item);
});
// substring search filter
$filteredStrpos = array_filter($a,function($item){
    return strpos($item,'000')!==FALSE;
});