繁体   English   中英

使用连接和LIKE查询性能

[英]Query performance with concatenation and LIKE

有人可以解释这3个查询之间的性能差异吗?

concat()函数:

explain analyze 
select * from person 
where (concat(last_name, ' ', first_name, ' ', middle_name) like '%Ива%');

Seq Scan on person  (cost=0.00..4.86 rows=1 width=15293) (actual time=0.032..0.140 rows=6 loops=1)
  Filter: (pg_catalog.concat(last_name, ' ', first_name, ' ', middle_name) ~~ '%Ива%'::text)
Total runtime: 0.178 ms

SQL标准与||连接

explain analyze 
select * from person 
where ((last_name || ' ' || first_name || ' ' || middle_name) like '%Ива%');

Seq Scan on person  (cost=0.00..5.28 rows=1 width=15293) (actual time=0.023..0.080 rows=6 loops=1)
  Filter: ((((((last_name)::text || ' '::text) || (first_name)::text) || ' '::text) || (middle_name)::text) ~~ '%Ива%'::text)
Total runtime: 0.121 ms

分别搜索字段:

explain analyze 
select * from person 
where (last_name like '%Ива%') or (first_name like '%Ива%') or (middle_name like '%Ива%');

Seq Scan on person  (cost=0.00..5.00 rows=1 width=15293) (actual time=0.018..0.060 rows=6 loops=1)
  Filter: (((last_name)::text ~~ '%Ива%'::text) OR ((first_name)::text ~~ '%Ива%'::text) OR ((middle_name)::text ~~ '%Ива%'::text))
Total runtime: 0.097 ms

为什么concat()最慢的一个,为什么几like快的条件?

虽然不是具体的答案,但以下内容可能会帮助您得出一些结论:

  1. 调用concat来连接三个字符串,或者使用|| 运算符,导致postgres必须分配一个新的缓冲区来保存连接的字符串,然后将字符复制到其中。 必须为每一行完成此操作。 然后缓冲区必须在最后解除分配。

  2. 如果您将三个条件ORing在一起,postgres可能只需要评估其中一个或两个,以决定是否必须包含该行。

  3. 有可能使用||表达式评估 与对concat的函数调用相比,运算符可能更有效,或者可能更容易优化。 我不会惊讶地发现内部操作员有一些特殊的案例处理。

  4. 正如评论中所提到的,您的样本太小,无论如何都无法做出正确的结论。 在几分之一毫秒的水平上,其他噪声因素可能会扭曲结果。

你到目前为止观察到的内容很有趣,但并不重要。 连接字符串的次要成本开销。

这些表达式之间更重要的区别并没有显示在没有索引的最小测试用例中。

前两个示例不是sargable (除非您构建定制的表达式索引):

where concat(last_name, ' ', first_name, ' ', middle_name) like '%Ива%'
where (last_name || ' ' || first_name || ' ' || middle_name) like '%Ива%'

虽然这个是:

where last_name like '%Ива%' or first_name like '%Ива%' or middle_name like '%Ива%'

即,它可以使用普通的三角形索引产生很好的效果(列的顺序在GIN索引中不重要):

CREATE INDEX some_idx ON person USING gin (first_name  gin_trgm_ops
                                         , middle_name gin_trgm_ops
                                         , last_name   gin_trgm_ops);

说明:

如果可以为NULL则测试不正确

concat()通常比使用||简单字符串连接稍贵 它也是不同的 :如果任何输入字符串是NULL,在第二种情况下连接结果也是NULL,但不是在第一种情况下,因为concat()只是忽略NULL值 - 但你仍然会得到一个无用的空间结果中的字符。

详细说明:

如果您正在寻找一个干净,优雅的表达(大约相同的成本),请使用concat_ws()代替:

concat_ws( ' ', last_name, first_name, middle_name)

此查询具有在每行上调用函数的开销

explain analyze 
select * from person 
where (concat(last_name, ' ', first_name, ' ', middle_name) like '%Ива%');

此查询更快,因为没有执行其他操作

explain analyze 
select * from person 
where (last_name like '%Ива%') or (first_name like '%Ива%') or (middle_name like '%Ива%');

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM