PostgreSQL LIKE和正则表达式之间的性能差异

dmi*_*kam 7 regex sql 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 name LIKE '%***%'; -- Total runtime 5.000 - 7.000 ms
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,LIKE运算符和简单正则表达式之间的差异是两倍以上(我认为LIKE运算符内部将转换为正则表达式,并且应该没有任何区别)

那里有近13000行,"name"列是"text"类型.没有与表中定义的"name"列相关的索引.

编辑:

解释他们的每一个:

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
Run Code Online (Sandbox Code Playgroud)
EXPLAIN ANALYZE SELECT count(*) as cnt FROM datos WHERE nombre ~ '\*\*\*';
Aggregate  (cost=894.32..894.33 rows=1 width=0) (actual time=17.404..17.405 rows=1 loops=1)
  ->  Seq Scan on datos  (cost=0.00..894.31 rows=1 width=0) (actual time=0.608..17.396 rows=25 loops=1)
        Filter: (nombre ~ '\*\*\*'::text)
Total runtime: 17.451 ms
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

Dan*_*ité 8

text LIKE text运算符(~~)是通过在特定的C代码实现like_match.c.它是与正则表达式完全独立的特殊代码.看一下这些评论,它显然已经过专门优化,只能实现%_作为通配符,并尽可能短路到退出,而正则表达式引擎则要复杂几个数量级.

请注意,在您的测试用例中,就像正则表达式相比较不理想LIKE,LIKE与之相比可能不是最理想的strpos(name, '***') > 0

strpos使用Boyer-Moore-Horspool算法实现,该算法针对搜索文本中几乎没有部分匹配的大子串进行了优化.

在内部,这些功能得到了合理的优化,但是当有多种方法可以达到同一目标时,选择最好的方法仍然是调用者的工作.PostgreSQL不会为我们分析匹配的模式,并根据该分析将a 切换regexp为a LIKE或a .LIKEstrpos