PSQL替换存储过程,速度太慢

时间:2017-04-24 13:28:54

标签: sql postgresql stored-procedures sqlperformance postgresql-performance

我有property,每个property都有contracts,每个contract都有整数字段rental_area

以前我必须得到财产总结的所有合同的rental_area,这是有效的。

 SELECT 
        Sum(cr.rental_area)         total_property_rental_area,
        -- bunch of other cr fields
 FROM  appdata.contract_rental cr
        INNER JOIN appdata.domain_building b1 
                ON ( b1.building_id = cr.building_id ) 
        INNER JOIN appdata.domain_immovable im1 
                ON ( im1.immovable_id = b1.immovable_id ) 
 GROUP  BY im1.property_id

现在逻辑已更改,并且合约有一个periods列表,其中一个句点包含该合约的rental_area。找到正确的period需要一些特殊的逻辑。

我试图将逻辑加入到查询中,但找不到一个地方,在哪里放置它所以我必须创建存储过程。

SELECT Sum(p.rental_area) total_property_rental_area 
       -- bunch of other cr fields
FROM   appdata.contract_rental cr 
       JOIN appdata.rental_period p 
         ON p.id = Get_current_period_id(cr.contract_rental_id, 
                   cr.end_date_actual) 
       INNER JOIN appdata.domain_building b1 
               ON ( b1.building_id = cr.building_id ) 
       INNER JOIN appdata.domain_immovable im1 
               ON ( im1.immovable_id = b1.immovable_id ) 
GROUP  BY im1.property_id   

步骤:

CREATE OR REPLACE FUNCTION appdata.get_current_period_id(in contract_id_in bigint, in end_date_actual_in Date)
  RETURNS bigint AS
$BODY$
DECLARE
    period_id bigint;
BEGIN
    -- find the period that matches with end date or current date
    select id into period_id
       from rental_period
       where contract_id = contract_id_in
         and Coalesce(end_date_actual_in, Now()) >= start_date
       order by start_date desc  limit 1;
    -- if there was no period, just take the first one
    IF period_id is null THEN
        select id into period_id
           from rental_period
           where contract_id = contract_id_in
           order by start_date asc
           limit 1;
    END IF;

    return period_id;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

但现在它太慢了,是否有办法将周期​​查找逻辑放入sql中以使其更快,而不使用存储过程? 重点是,对于达成合同,它必须只根据逻辑获得单个期间。

1 个答案:

答案 0 :(得分:1)

将存储过程转出回主SQL,主要提示正在合并你的2个查询(如果一个为null则使用另一个)

示例:而不是

p.id = Get_current_period_id(cr.contract_rental_id, 
               cr.end_date_actual)

使用:

p.pid = coalesce(
    (select rpx.id 
     from rental_period rpx
     where contract_id = cr.contract_rental_id
     and Coalesce(cr.end_date, Now()) >= start_date
     order by start_date desc  limit 1;
    ),
  ( select rpy.id 
       from rental_period rpy
       where contract_id = cr.contract_rental_id
       order by start_date asc
       limit 1;
  )
)

根据以下评论,以下索引也可能有所帮助:

 create index on rental_period (contract_id, start_date asc) 

请务必在之后分析表格以更新统计数据。