2012-04-16 166 views
3
        QUERY PLAN         
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Unique (cost=32164.87..32164.89 rows=1 width=44) (actual time=221552.831..221552.831 rows=0 loops=1) 
    -> Sort (cost=32164.87..32164.87 rows=1 width=44) (actual time=221552.827..221552.827 rows=0 loops=1) 
     Sort Key: t.date_effective, t.acct_account_transaction_id, p.method, t.amount, c.business_name, t.amount 
     -> Nested Loop (cost=22871.67..32164.86 rows=1 width=44) (actual time=221552.808..221552.808 rows=0 loops=1) 
       -> Nested Loop (cost=22871.67..32160.37 rows=1 width=52) (actual time=221431.071..221546.619 rows=670 loops=1) 
        -> Nested Loop (cost=22871.67..32157.33 rows=1 width=43) (actual time=221421.218..221525.056 rows=2571 loops=1) 
          -> Hash Join (cost=22871.67..32152.80 rows=1 width=16) (actual time=221307.382..221491.019 rows=2593 loops=1) 
           Hash Cond: ("outer".acct_account_id = "inner".acct_account_fk) 
           -> Seq Scan on acct_account a (cost=0.00..7456.08 rows=365008 width=8) (actual time=0.032..118.369 rows=61295 loops=1) 
           -> Hash (cost=22871.67..22871.67 rows=1 width=16) (actual time=221286.733..221286.733 rows=2593 loops=1) 
             -> Nested Loop Left Join (cost=0.00..22871.67 rows=1 width=16) (actual time=1025.396..221266.357 rows=2593 loops=1) 
              Join Filter: ("inner".orig_acct_payment_fk = "outer".acct_account_transaction_id) 
              Filter: ("inner".link_type IS NULL) 
              -> Seq Scan on acct_account_transaction t (cost=0.00..18222.98 rows=1 width=16) (actual time=949.081..976.432 rows=2596 loops=1) 
                Filter: ((("type")::text = 'debit'::text) AND ((transaction_status)::text = 'active'::text) AND (date_effective >= '2012-03-01'::date) AND (date_effective < '2012-04-01 00:00:00'::timestamp without time zone)) 
              -> Seq Scan on acct_payment_link l (cost=0.00..4648.68 rows=1 width=15) (actual time=1.073..84.610 rows=169 loops=2596) 
                Filter: ((link_type)::text ~~ 'return_%'::text) 
          -> Index Scan using contact_pk on contact c (cost=0.00..4.52 rows=1 width=27) (actual time=0.007..0.008 rows=1 loops=2593) 
           Index Cond: (c.contact_id = "outer".contact_fk) 
        -> Index Scan using acct_payment_transaction_fk on acct_payment p (cost=0.00..3.02 rows=1 width=13) (actual time=0.005..0.005 rows=0 loops=2571) 
          Index Cond: (p.acct_account_transaction_fk = "outer".acct_account_transaction_id) 
          Filter: ((method)::text <> 'trade'::text) 
       -> Index Scan using contact_role_pk on contact_role (cost=0.00..4.48 rows=1 width=4) (actual time=0.007..0.007 rows=0 loops=670) 
        Index Cond: ("outer".contact_id = contact_role.contact_fk) 
        Filter: (exchange_fk = 74) 
Total runtime: 221553.019 ms 
+1

這裏是一個更可讀的格式計劃:http://explain.depesz.com/s/12r – 2012-04-16 10:38:39

+1

你應該重新寫你的SQL查詢來** **僅使用顯式JOIN句法。你在混合隱式連接和顯式連接,這是一個壞主意。 – 2012-04-16 10:40:13

+0

'FROM ...,acct_account a,acct_payment p,...'我沒有看到這些表的任何連接字段。可能會導致笛卡爾產品。 – wildplasser 2012-04-16 10:55:26

回答

4

你的問題是在這裏:

-> Nested Loop Left Join (cost=0.00..22871.67 rows=1 width=16) (actual time=1025.396..221266.357 rows=2593 loops=1) 
    Join Filter: ("inner".orig_acct_payment_fk = "outer".acct_account_transaction_id) 
    Filter: ("inner".link_type IS NULL) 
     -> Seq Scan on acct_account_transaction t (cost=0.00..18222.98 rows=1 width=16) (actual time=949.081..976.432 rows=2596 loops=1) 
       Filter: ((("type")::text = 'debit'::text) AND ((transaction_status)::text = 'active'::text) AND (date_effective >= '2012-03-01'::date) AND (date_effective 
      Seq Scan on acct_payment_link l (cost=0.00..4648.68 rows=1 width=15) (actual time=1.073..84.610 rows=169 loops=2596) 
       Filter: ((link_type)::text ~~ 'return_%'::text) 

它希望找到在acct_account_transaction 1列,而它找到2596,以及類似的其他表。

你沒有提到你的Postgres版本(可能嗎?),但是這應該做的伎倆:

SELECT DISTINCT 
    t.date_effective, 
    t.acct_account_transaction_id, 
    p.method, 
    t.amount, 
    c.business_name, 
    t.amount 
FROM 
    contact c inner join contact_role on (c.contact_id=contact_role.contact_fk and contact_role.exchange_fk=74), 
    acct_account a, acct_payment p, 
    acct_account_transaction t 
WHERE 
    p.acct_account_transaction_fk=t.acct_account_transaction_id 
    and t.type = 'debit' 
    and transaction_status = 'active' 
    and p.method != 'trade' 
    and t.date_effective >= '2012-03-01' 
    and t.date_effective < (date '2012-03-01' + interval '1 month') 
    and c.contact_id=a.contact_fk and a.acct_account_id = t.acct_account_fk 
    and not exists(
     select * from acct_payment_link l 
      where orig_acct_payment_fk == acct_account_transaction_id 
      and link_type like 'return_%' 
    ) 
ORDER BY 
    t.date_effective DESC 

另外,儘量設置適當的統計目標相關列。鏈接到友好手冊:http://www.postgresql.org/docs/current/static/sql-altertable.html

0

我刪除了我的第一個建議,因爲它改變了查詢的性質。

我發現在LEFT JOIN上花費的時間太多。

  1. 第一件事就是試着只對acct_payment_link表進行一次掃描。你可以嘗試重寫你的查詢:

    ... LEFT JOIN (SELECT * FROM acct_payment_link 
           WHERE link_type LIKE 'return_%') AS l ... 
    
  2. 您應該檢查你的統計數據,因爲這行的計劃,並返回數字之間的差異。

  3. 你還沒有包括表和索引的定義,所以看看這些是很好的。

  4. 您可能還想使用contrib/pg_tgrm擴展來構建acct_payment_link.link_type上的索引,但我會讓這是最後一個選項。

順便說一句,你正在使用什麼PostgreSQL版本?

+1

但這將有效地將左連接更改爲內連接 – 2012-04-16 11:09:15

+0

是的,我很傻。呃... – vyegorov 2012-04-16 11:18:09

0

你的索引是什麼?最近你有分析過嗎?它做的acct_account_transaction表掃描即使有該表上的幾個標準:

  • date_effective

如果對這些列沒有索引,那麼複合一一(type, date_effective)可能幫助(假設有很多行不符合這些列的標準)。

0

你的聲明改寫和格式化:

SELECT DISTINCT 
     t.date_effective, 
     t.acct_account_transaction_id, 
     p.method, 
     t.amount, 
     c.business_name, 
     t.amount 
FROM contact     c 
JOIN contact_role   cr ON cr.contact_fk = c.contact_id 
JOIN acct_account    a ON a.contact_fk = c.contact_id 
JOIN acct_account_transaction t ON t.acct_account_fk = a.acct_account_id 
JOIN acct_payment    p ON p.acct_account_transaction_fk 
            = t.acct_account_transaction_id 
LEFT JOIN acct_payment_link l ON orig_acct_payment_fk 
            = acct_account_transaction_id 
             -- missing table-qualification! 
           AND link_type like 'return_%' 
             -- missing table-qualification! 
WHERE transaction_status = 'active' -- missing table-qualification! 
AND cr.exchange_fk = 74 
AND t.type = 'debit' 
AND t.date_effective >= '2012-03-01' 
AND t.date_effective < (date '2012-03-01' + interval '1 month') 
AND p.method != 'trade' 
AND l.link_type IS NULL 
ORDER BY t.date_effective DESC; 
  • 顯式連接語句是優選的。我根據你的JOIN邏輯重新排序你的表格。

  • 爲什麼(date '2012-03-01' + interval '1 month')代替日期'2012-04-01'

  • 缺少一些表格資格。在這種複雜的聲明中,這是一種糟糕的風格。可能會隱藏一個錯誤。

性能的關鍵是指標在適當情況下,適當的配置的PostgreSQL,準確統計

General advice on performance tuning in the PostgreSQL wiki.