[英]SQL query LIKE from another table
我有一個 SQL 查詢,它從另一個表中獲取值並放入 LIKE %%:
SELECT
*
FROM
contacts xa
WHERE
lower(xa.title) in (
select
lower(title)
from
contacts con
inner join ce_campaign_spec_tb camp on lower(con.title) ilike '%' || trim(
both ' '
from
camp.param_val
) || '%'
where
job_id = '18649b38-ce57-48ba-ac52-9e95085df3f9'
and param = 'title'
and relation_id = 1
)
執行上述查詢需要 2 分鍾。 如何重寫此查詢以更好地執行?
解釋看起來像這樣:
XN Hash IN Join DS_BCAST_INNER (cost=1183647.16..12653156935.52 rows=2075741 width=801)
Hash Cond: (lower(("outer".title)::text) = lower(("inner".title)::text))
-> XN Seq Scan on contacts xa (cost=0.00..20757.41 rows=2075741 width=801)
-> XN Hash (cost=1183569.31..1183569.31 rows=31137 width=32)
-> XN Nested Loop DS_BCAST_INNER (cost=427.16..1183569.31 rows=31137 width=32)
Join Filter: (lower(("outer".title)::text) ~~* (('%'::text || btrim(("inner".param_val)::text, ' '::text)) || '%'::text))
-> XN Seq Scan on contacts con (cost=0.00..20757.41 rows=2075741 width=32)
-> XN Materialize (cost=427.16..427.19 rows=3 width=21)
-> XN Seq Scan on ce_campaign_spec_tb camp (cost=0.00..331.15 rows=3 width=21)
Filter: (((job_id)::text = '18649b38-ce57-48ba-ac52-9e95085df3f9'::text) AND ((relation_id)::text = '1'::text) AND ((param)::text = 'title'::text))
----- Nested Loop Join in the query plan - review the join predicates to avoid Cartesian products -----
EXPLAIN 計划表明最大的成本是:
XN Hash IN Join DS_BCAST_INNER (cost=1183647.16..12653156935.52 rows=2075741 width=801)
這是整個IN
子選擇,有 200 萬行。 此外,它指示DS_BCAST_INNER
,它在Evaluating the query plan - Amazon Redshift上定義為“整個內部表的副本廣播到所有計算節點”。
因此,它基本上是在說它在節點之間發送大量數據,並且每一行都需要通過lower()
轉換值,因此很難使查詢高效。
首先,確保表使用適當的分發鍵 ( DISTKEY
) 和排序鍵 ( SORTKEY
)。 表被廣播到所有計算節點的事實表明這些表沒有分布在同一個鍵上。 一個好的經驗法則是DISTKEY
應該設置為JOINs
中最常用的字段。 因此,請檢查contacts
和ce_campaign_spec_tb
是否具有與其DISTKEY
具有相同值的列,並避免在 JOINed 值中使用計算(即連接原始列而不是從列值計算的值),因為這將避免任何無論如何都可以從使用DISTKEY
中受益。
INNER JOIN
的開銷也很大,可能是因為連接的復雜性(lower、ilike、trim)。 如果可能,請預先計算此轉換並將其存儲為另一個字段。 如果可以簡化查詢以匹配實際值而無需任何轉換(例如lower()
和ilike
),那么數據庫可以大大優化查詢。 數據倉庫中的一個重要概念是擁有寬表,這意味着您可以創建可能重復數據的額外列,但更容易查詢。 例如,您可以在每個合同上存儲一個小寫的標題,以避免在每個查詢中將其轉換為小寫。
我也不明白為什么它首先要執行IN
子查詢。 它基本上是在說:
SELECT contract where contract IN (SELECT contract where...)
你能去掉那個外面的 select 嗎? 這將避免再次在contracts
表中移動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.