[英]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
快的條件?
雖然不是具體的答案,但以下內容可能會幫助您得出一些結論:
調用concat
來連接三個字符串,或者使用||
運算符,導致postgres必須分配一個新的緩沖區來保存連接的字符串,然后將字符復制到其中。 必須為每一行完成此操作。 然后緩沖區必須在最后解除分配。
如果您將三個條件ORing在一起,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,在第二種情況下連接結果也是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.