PSQL 替换存储过程,太慢
PSQL replacement for stored procedure, too slow
我有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里面,让它更快,而不用存储过程? 重点是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 以更新统计数据。
我有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里面,让它更快,而不用存储过程? 重点是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 以更新统计数据。