【发布时间】:2017-04-24 13:28:53
【问题描述】:
我有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里面让它更快呢? 关键是,要达成合约,根据逻辑只能得到一个周期。
【问题讨论】:
-
题外话:你可以避免
Coalesce(end_date_actual_in, Now())构造,方法是让 start_date 和 end_date 不可为空,并给它们默认值-infinity和+infinity。 -
@joop ,但是我必须检查该值是 -infinity 还是 +infinity 而不是 null,所以我认为性能方面是相同的。同样在 UI 中,它们将始终被视为某些值,并会尝试在那里显示它们,而不是显示空字段。
标签: sql postgresql stored-procedures sqlperformance postgresql-performance