简体   繁体   English

使用连接和LIKE查询性能

[英]Query performance with concatenation and LIKE

Can someone explain the performance difference between these 3 queries? 有人可以解释这3个查询之间的性能差异吗?

concat() function: 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 standard concatenation with || 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

Search fields separately: 分别搜索字段:

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

Why is concat() slowest one and why are several like conditions faster? 为什么concat()最慢的一个,为什么几like快的条件?

While not a concrete answer, the following might help you to reach some conclusions: 虽然不是具体的答案,但以下内容可能会帮助您得出一些结论:

  1. Calling concat to concatenate the three strings, or using the || 调用concat来连接三个字符串,或者使用|| operator, results in postgres having to allocate a new buffer to hold the concatenated string, then copy the characters into it. 运算符,导致postgres必须分配一个新的缓冲区来保存连接的字符串,然后将字符复制到其中。 This has to be done for each row. 必须为每一行完成此操作。 Then the buffer has to be deallocated at the end. 然后缓冲区必须在最后解除分配。

  2. In the case where you are ORing together three conditions, postgres may only have to evaluate only one or maybe two of them to decide if it has to include the row. 如果您将三个条件ORing在一起,postgres可能只需要评估其中一个或两个,以决定是否必须包含该行。

  3. It is possible that expression evaluation using the || 有可能使用||表达式评估 operator might be more efficient, or perhaps more easily optimizable, compared with a function call to concat . 与对concat的函数调用相比,运算符可能更有效,或者可能更容易优化。 I would not be surprised to find that there is some special case handling for internal operators. 我不会惊讶地发现内部操作员有一些特殊的案例处理。

  4. As mentioned in the comments, your sample is too small to make proper conclusions anyway. 正如评论中所提到的,您的样本太小,无论如何都无法做出正确的结论。 At the level of a fraction of a millisecond, other noise factors can distort the result. 在几分之一毫秒的水平上,其他噪声因素可能会扭曲结果。

What you have observed so far is interesting but hardly important. 你到目前为止观察到的内容很有趣,但并不重要。 Minor cost overhead for concatenating strings. 连接字符串的次要成本开销。

The much more important difference between these expressions does not show in your minimal test case without indexes. 这些表达式之间更重要的区别并没有显示在没有索引的最小测试用例中。

The first two examples are not sargable (unless you build a tailored expression index): 前两个示例不是sargable (除非您构建定制的表达式索引):

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

While this one is: 虽然这个是:

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

Ie, it can use a plain trigram index to great effect (order of columns is unimportant in a GIN index): 即,它可以使用普通的三角形索引产生很好的效果(列的顺序在GIN索引中不重要):

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

Instructions: 说明:

Incorrect test if NULL is possible 如果可以为NULL则测试不正确

concat() is generally slightly more expensive than simple string concatenation with || concat()通常比使用||简单字符串连接稍贵 . It is also different : If any of the input strings is NULL, the concatenated result is also NULL in your second case, but not in your first case, since concat() just ignores NULL values - but you'd still get a useless space character in the result. 它也是不同的 :如果任何输入字符串是NULL,在第二种情况下连接结果也是NULL,但不是在第一种情况下,因为concat()只是忽略NULL值 - 但你仍然会得到一个无用的空间结果中的字符。

Detailed explanation: 详细说明:

If you are looking for a clean, elegant expression (about the same cost), use concat_ws() instead: 如果您正在寻找一个干净,优雅的表达(大约相同的成本),请使用concat_ws()代替:

concat_ws( ' ', last_name, first_name, middle_name)

This query has overhead for calling function on each row 此查询具有在每行上调用函数的开销

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

this query is faster cause no additional operation executed 此查询更快,因为没有执行其他操作

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