有人能解释这三个查询之间的性能差异?
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
条件更快?
虽然没有一个具体的答案,下面可能会帮助你达成一些结论:
concat
以连接三根弦,或使用||
操作,导致Postgres的具有分配一个新的缓冲区来保存连接字符串,然后将字符复制到它。这对每一行做。然后将缓冲液具有在端部被解除分配。||
操作表达式求值可能更有效,或者更容易优化的,用一个函数调用concat
比较。我也不会感到惊讶地发现,有一些特殊的情况下处理内部的运营商。什么到目前为止,你已经观察到的是有趣的,但几乎没有重要的。未成年人的成本开销用于连接字符串。
这些表达之间的更为重要的区别并不在最小的测试案例表明没有索引。
前两个实施例不是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);
说明:
concat()
一般略高于简单的字符串连接与||
更加昂贵。这也是不同的:如果任何输入的字符串为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 '%Ива%');