将大型查询(2天)拆分为多个部分以提高Postgres的速度

时间:2015-06-09 09:06:19

标签: sql performance postgresql function loops

我正在对包含超过1.2亿行和200列的数据库运行查询。数据集包含贷款信息,我们为每个借款人提供大约15行(每季度一次观察),而borrowerID也是主要密钥。我也加入了这个borrowerID来检索上一季度的信息,我明白这使得我的查询非常复杂。该数据库还包含Bank上的FK(外键)。托管数据库的一方向我解释说,如果我编写一个函数来按部分运行查询,那么它会更快。目前我的查询看起来像这样。

SELECT a.id.   
   a.arrears AS "Months in Arrears",
   a.balance AS "Original Balance",
   a.bank AS "Bank",
   b.arrears AS "Next Months in Arrears",
   b.balance AS "Next Original Balance",

dense_rank() OVER (PARTITION BY concat(a.bank, a.id), ("substring"(a.date::text, 1, 4) || 'Q'::text) || round(0.3333 + "substring"(a.date::text, 6, 2)::numeric / 3::numeric, 0) ORDER BY a.date DESC) AS "Duplicate",
FROM loandata a
LEFT JOIN loandata b ON a.bank::text = b.bank::text AND a.id::text = b.id::text AND round((b.date::date - a.date::date)::numeric / 30::numeric, 0) = 3::numeric
ALTER TABLE myview
OWNER TO me;
GRANT ALL ON TABLE myview TO me;

你能帮我写一个函数,这个查询是由银行执行的,或者每个id执行它是否有意义,因为它是主键?我正在运行此视图以在Tableau中下载和存储数据。

非常感谢提前。 最好的,蒂姆

PS。 dense_rank函数用于查找每季度有多个观察值的贷款。

评论中建议的解释分析结果可以在这里找到: http://explain.depesz.com/s/K19 我使用了数据的一个子集,我选择了1个银行。

2 个答案:

答案 0 :(得分:2)

我不太确定查询的确切意图,但使用日期函数而不是数值类型的计算,并且避免所有强制转换和concat()可能会让你到达某个地方。

SELECT a.id
   , a.arrears AS "Months in Arrears"
   , a.balance AS "Original Balance"
   , a.bank AS "Bank"
   , b.arrears AS "Next Months in Arrears"
   , b.balance AS "Next Original Balance"

   , dense_rank() OVER (
      PARTITION BY a.bank, a.id, date_trunc( 'quarter' ,a.date )
      ORDER BY a.date DESC
      ) AS "Duplicate"
FROM loandata a
LEFT JOIN loandata b ON a.bank = b.bank
    AND a.id = b.id
    AND date_trunc( 'quarter', b.date ) 
      = date_trunc( 'quarter', a.date + 'quarter'::interval) )
        ;

BTW:不要使用名为date的列。它是SQL中的类型名称(在我的编辑器中以绿色突出显示)

答案 1 :(得分:0)

我建议修改一下:

LEFT JOIN loandata b ON a.bank::text = b.bank::text AND a.id::text = b.id::text AND round((b.date::date - a.date::date)::numeric / 30::numeric, 0) = 3::numeric

...到......

LEFT JOIN loan data b
  ON a.bank = b.bank AND
     a.id   = b.id   AND
     b.date between (a.date + 75) and (a.date + 105)

虽然,我不确定你的日期逻辑是你想要的。如果您可以用文字描述您想要的内容,那么可以使用更好的方法。

https://wiki.postgresql.org/wiki/Working_with_Dates_and_Times_in_PostgreSQL