与级联和LIKE查询性能

问题描述 投票:2回答: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条件更快?

sql postgresql pattern-matching concatenation postgresql-performance
3个回答
4
投票

虽然没有一个具体的答案,下面可能会帮助你达成一些结论:

  1. 调用concat以连接三根弦,或使用||操作,导致Postgres的具有分配一个新的缓冲区来保存连接字符串,然后将字符复制到它。这对每一行做。然后将缓冲液具有在端部被解除分配。
  2. 在你或运算三个条件在一起的情况下,Postgres的可能只需要评价只有一个或者两个人来决定,如果它必须包括该行。
  3. 这可能是使用||操作表达式求值可能更有效,或者更容易优化的,用一个函数调用concat比较。我也不会感到惊讶地发现,有一些特殊的情况下处理内部的运营商。
  4. 正如在评论中提到,你的样本太小,无法做出正确的结论呢。在一毫秒的一小部分的水平,其他噪声因素干扰的结果。

2
投票

什么到目前为止,你已经观察到的是有趣的,但几乎没有重要的。未成年人的成本开销用于连接字符串。

这些表达之间的更为重要的区别并不在最小的测试案例表明没有索引。

前两个实施例不是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);

说明:

Incorrect test if NULL is possible

concat()一般略高于简单的字符串连接与||更加昂贵。这也是不同的:如果任何输入的字符串为NULL,则连接的结果也是空在第二种情况下,但不是在你的第一个情况下,由于concat()会忽略NULL值 - 但你还是会得到一个无用的空格字符结果。

详细说明:

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

concat_ws( ' ', last_name, first_name, middle_name)

0
投票

此查询有开销每行调用函数

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 '%Ива%');
© www.soinside.com 2019 - 2024. All rights reserved.