簡體   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