2017-04-14 49 views
0

我試圖在postgres中將三個錶鏈接在一起。

所有三個表都是從子查詢生成的。第一個表通過變量call_sign作爲FULL JOIN鏈接到第二個表(因爲我想要來自兩個表的條​​目的超集)。第三個表與call_sign上的第二個表也有INNER JOIN(理論上可能已經鏈接到第一個表)

查詢運行但速度很慢,我感覺隨着添加更多數據會變得更慢。我意識到我可以做某些事情來加速事情 - 比如不在子查詢中抽取不必要的數據,也不會將文本轉換爲數字。但是,有沒有更好的方法來構建這三個表之間的JOIN?

任何意見,將不勝感激,因爲我是postgres的新手。更有效的方式在Postgres中一起加入三個表

下面是代碼:

select 
(CASE 
    WHEN tmp1.frequency_assigned is NULL 
    THEN tmp2.lower_frequency 
    ELSE tmp1.frequency_assigned END) as master_frequency, 
(CASE 
    WHEN tmp1.call_sign is NULL 
    THEN tmp2.call_sign 
    ELSE tmp1.call_sign END) as master_call_sign, 
(CASE 
    WHEN tmp1.entity_type is NULL 
    THEN tmp2.entity_type 
    ELSE tmp1.entity_type END) as master_entity_type, 
(CASE 
    WHEN tmp1.licensee_id is NULL 
    THEN tmp2.licensee_id 
    ELSE tmp1.licensee_id END) as master_licensee_id, 
(CASE 
    WHEN tmp1.entity_name is NULL 
    THEN tmp2.entity_name 
    ELSE tmp1.entity_name END) as master_entity_name, 
tmp3.market_name  
FROM 
    (select cast(replace(frequency_assigned, ',','.') as decimal) AS frequency_assigned, 
    frequency_upper_band, 
    f.uls_file_number, 
    f.call_sign, 
    entity_type, 
    licensee_id, 
    entity_name 
    from combo_fr f INNER JOIN combo_en e 
    ON f.call_sign=e.call_sign 
    ORDER BY frequency_assigned DESC) tmp1 
FULL JOIN 
    (select cast(replace(lower_frequency, ',','.') as decimal) AS lower_frequency, 
    upper_frequency, 
    e.uls_file_number, 
    mf.call_sign, 
    entity_type, 
    licensee_id, 
    entity_name 
    FROM market_mf mf INNER JOIN combo_en e 
    ON mf.call_sign=e.call_sign 
    ORDER BY lower_frequency DESC) tmp2 
ON tmp1.call_sign=tmp2.call_sign 
INNER JOIN 
    (select en.call_sign, 
    mk.market_name 
    FROM combo_mk mk 
    INNER JOIN combo_en en 
    ON mk.call_sign=en.call_sign) tmp3 
ON tmp2.call_sign=tmp3.call_sign 
ORDER BY master_frequency DESC; 
+4

首先,您可以使用['COALESCE'](https://www.postgresql.org/docs/current/static/functions-conditional.html#FUNCTIONS-COALESCE-NVL-IFNULL)而不是' CASE WHEN ... IS NULL'。 – kennytm

+3

其次,你應該刪除子查詢中的所有'ORDER BY',在這種情況下這是完全無用的。 – Dario

+0

在任何涉及的表格中,「call_sign'是可空的還是唯一的?其他領域是否可以空?換句話說,這些'CASE WHEN ...'是否會返回來自同一個表的每一行的值,或者可能會出現這樣的情況:答案中的某一行是來自'combo_fr'和'market_mf'的值的混合值(忽略'call_sign')? – Dario

回答

0

你要放鬆這些查詢,做這一切在一個連接,如果你能。 Soemthing像:

select <whatever you need> 
from combo_fr f 
JOIN combo_en e ON f.call_sign=e.call_sign 
JOIN market_mf mf mf ON mf.call_sign=e.call_sign 
JOIN combo_mk mk ON mk.call_sign=en.call_sign 

我不能完全神交你在做什麼,但一些加盟條款可能會成爲留在爲了應對在呼號或不出現的地方連接。

0

所有四個涉及的表上call_sign創建索引後,試試這個:

WITH nodup AS (
    SELECT call_sign FROM market_mf 
    EXCEPT SELECT call_sign FROM combo_fr 
) SELECT  
     CAST(REPLACE(u.master_frequency_string, ',','.') AS DECIMAL) 
       AS master_frequency, 
     u.call_sign AS master_call_sign, 
     u.entity_type AS master_entity_type, 
     u.licensee_id AS master_licensee_id, 
     u.entity_name AS master_entity_name, 
     combo_mk.market_name 
    FROM (SELECT frequency_assigned AS master_frequency_string, call_sign, 
       entity_type, licensee_id, entity_name 
      FROM combo_fr 
      UNION ALL SELECT lower_frequency, call_sign, 
       entity_type, licensee_id, entity_name 
      FROM market_mf INNER JOIN nodup USING (call_sign) 
    ) AS u 
    INNER JOIN combo_en USING (call_sign) 
    INNER JOIN combo_mk USING (call_sign) 
    ORDER BY 1 DESC; 

我張貼這一點,因爲這是瞭解你所需要的最簡單的方法。

  • 如果存在,其出現在兩個market_mfcombo_frWITH nodup ...INNER JOIN nodup ...可以省略無call_sign值。
  • 我假設call_signcombo_frmarket_mf(=每個表中沒有兩個記錄具有相同的值)中是唯一的,即使可能存在兩個表中都可能出現的值。
  • 這是非常不幸的,你命令一個計算列,並且計算是如此愚蠢。一定的優化將是在表格本身中一次或全部轉換頻率字符串。步驟是: (1)將數字頻率列添加到表中(2)使用從當前文本列轉換的值填充它們(3)將新值直接轉換爲新列,方法是輸入它們的語言環境所需的小數點分隔符。
+0

@Dario ....在call_sign上創建索引肯定有所改進。非常感謝。我也會做你建議的最後一步,並在新列中轉換那些應該是數字的文本列 – user3003374

+0

@ user3003374這是否意味着使用'UNION'和後續兩個'INNER JOIN'的方法是錯誤或正確的,但是比你原來的還差? – Dario