PSQL 替换存储过程,太慢

PSQL replacement for stored procedure, too slow

我有property,每个propertycontracts,每个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里面,让它更快,而不用存储过程? 重点是reach合约,按逻辑只需要单周期

将您的存储过程转回主程序 SQL,主要提示是合并您的 2 个查询(如果一个为空,则使用另一个)

示例:而不是

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) 

之后一定要分析 table 以更新统计数据。