我只是将数据从生产服务器转储到本地服务器以进行测试。我们的应用程序使用大约300行sql的存储过程。此过程在服务器数据库中正常工作,但每次在我的本地数据库上运行它时都会卡住(永远运行)。有没有人对它为何陷入困境有任何想法。 这是我转储数据的命令。
CREATE OR REPLACE FUNCTION public.insert_hm_ticket_statistic(v_sprint_id bigint)
RETURNS integer
LANGUAGE plpgsql
AS $$
DECLARE
v_ticket INT;
v_startsprint_date DATE;
v_end_date DATE;
v_current_date DATE;
v_first_activity_date DATE;
v_started DATE;
v_sprint_setting VARCHAR(255);
v_time_spent_second FLOAT;
v_remaining_estimate FLOAT;
v_time_logged_tmp FLOAT;
v_has_log INT;
v_time_logged_tk FLOAT;
v_oe_tk INT;
v_has_past_sprint INT;
v_oe_sprint INT;
v_complete_of_sprint FLOAT;
v_oe_tk_burnt FLOAT;
v_oe_sprint_burnt FLOAT;
v_project_complete FLOAT;
v_complete_tk FLOAT;
rl_cursor CURSOR FOR SELECT
tk.id,
tk.has_past_sprint,
cast(first_activity_date AS DATE)
FROM hm_ticket tk
WHERE sprint = v_sprint_id AND deleted = 0;
BEGIN
-- find start date and end date of sprint
SELECT
cast(start_date AS DATE),
cast(end_date AS DATE)
INTO v_startsprint_date, v_end_date
FROM hm_sprint
WHERE id = v_sprint_id AND status <> 'future';
-- find sprint setting
IF NOT exists(SELECT d.burn_down_statuses
FROM hm_sprint x, hm_setting c, hm_burn_down_status d
WHERE c.id = d.setting AND x.setting = c.id AND x.id = v_sprint_id)
THEN
v_sprint_setting :='xxx';
ELSE
SELECT string_agg(d.burn_down_statuses, ',')
INTO v_sprint_setting
FROM hm_sprint x, hm_setting c, hm_burn_down_status d
WHERE c.id = d.setting AND x.setting = c.id AND x.id = v_sprint_id;
END IF;
raise notice 'v_sprint_setting %', v_sprint_setting;
OPEN rl_cursor;
LOOP
FETCH rl_cursor INTO v_ticket, v_has_past_sprint, v_first_activity_date;
raise notice 'v_ticket: %', v_ticket;
EXIT WHEN NOT FOUND;
/*select cast(min(started) as date) into v_started
from hm_worklog
where ticket=v_ticket and cast(started as date) between v_startsprint_date and v_end_date;
if v_started is null then v_current_date:=v_startsprint_date;
else
v_current_date:=v_started;
end if;*/
v_current_date:=v_startsprint_date;
--- calculate remaining estimate, time logged of ticket
IF v_has_past_sprint = 0
THEN
SELECT
coalesce(remaining_estimate, 0),
coalesce(time_logged, 0)
INTO v_remaining_estimate, v_time_logged_tk
FROM hm_ticket
WHERE id = v_ticket;
ELSE
SELECT coalesce(time_logged, 0)
INTO v_time_logged_tmp
FROM hm_ticket
WHERE id = v_ticket;
--------------------------------------
SELECT
coalesce(remaining_estimate, 0),
v_time_logged_tmp - coalesce(time_logged, 0)
INTO v_remaining_estimate, v_time_logged_tk
FROM hm_ticket_past_sprint
WHERE ticket = v_ticket;
END IF;
raise notice '----------v_has_past_sprint: %', v_has_past_sprint;
raise notice '----------v_time_logged_tmp: %', v_time_logged_tmp;
raise notice '----------v_time_logged_tk: %', v_time_logged_tk;
raise notice '----------v_remaining_estimate: %', v_remaining_estimate;
-- calculate oe of ticket
IF v_has_past_sprint = 0
THEN
SELECT cast(CASE WHEN coalesce(original_estimate, 0) = 0
THEN coalesce(time_logged, 0)
ELSE original_estimate
END
AS FLOAT)
INTO v_oe_tk
FROM hm_ticket
WHERE id = v_ticket;
ELSE
SELECT coalesce(time_logged, 0)
INTO v_time_logged_tmp
FROM hm_ticket
WHERE id = v_ticket;
--------------------------------------
SELECT cast(CASE WHEN coalesce(original_estimate, 0) = 0
THEN v_time_logged_tmp - coalesce(time_logged, 0)
ELSE original_estimate
END
AS FLOAT)
INTO v_oe_tk
FROM hm_ticket_past_sprint
WHERE ticket = v_ticket;
END IF;
raise notice 'v_oe_tk: %',v_oe_tk;
/*########################################################################## START TO LOOP CURRENT DATE #############################################################################*/
WHILE v_current_date <= v_end_date LOOP
--- calculate time_spent_seconds from start sprint
IF NOT exists(SELECT id
FROM hm_worklog
WHERE ticket = v_ticket AND cast(started AS DATE) BETWEEN v_startsprint_date AND v_current_date)
THEN
v_time_spent_second:=0;
ELSE
SELECT cast(sum(time_spent_seconds) AS FLOAT)
INTO v_time_spent_second
FROM hm_worklog
WHERE ticket = v_ticket AND cast(started AS DATE) BETWEEN v_startsprint_date AND v_current_date
GROUP BY ticket;
END IF;
raise notice 'v_time_spent_second: %', v_time_spent_second;
--calculate % complete of ticket/day
IF NOT v_current_date = v_end_date THEN
IF NOT exists(SELECT date FROM hm_ticket_history WHERE ticket = v_ticket AND cast(date AS DATE) = v_current_date)
then
-- FIND STATUS OF TICKET IN SETTING. 0: NO STATUS EXIST -> FORMULAR SHOULD BE APPLIED , <>0 : EXIST--> SET COMPLETE TK = 0
SELECT CASE WHEN (position(upper(trim(status)) IN upper(trim(v_sprint_setting))) = 0)
THEN CASE WHEN v_remaining_estimate = 0 AND v_time_logged_tk <> 0 THEN 80
WHEN v_remaining_estimate = 0 AND v_time_logged_tk = 0 THEN 0
WHEN (v_remaining_estimate + v_time_logged_tk) = 0 THEN 0
ELSE round(cast(v_time_spent_second * 100 / (v_time_logged_tk + v_remaining_estimate) AS NUMERIC), 2)
END
ELSE 100
END AS complete
INTO v_complete_tk
FROM hm_ticket
WHERE id = v_ticket;
ELSE
SELECT CASE WHEN (position(upper(trim(status)) IN upper(trim(v_sprint_setting))) = 0)
THEN CASE WHEN v_remaining_estimate = 0 AND v_time_logged_tk <> 0 THEN 80
WHEN v_remaining_estimate = 0 AND v_time_logged_tk = 0 THEN 0
WHEN (v_remaining_estimate + v_time_logged_tk) = 0 THEN 0
ELSE round(cast(v_time_spent_second * 100 / (v_time_logged_tk + v_remaining_estimate) AS NUMERIC), 2)
END
ELSE 100
END AS complete
INTO v_complete_tk
FROM hm_ticket_history
WHERE ticket = v_ticket AND cast("date" AS DATE)= v_current_date;
END IF;
ELSE
--NOTE: IF V_CURRENT_DATE == END-DATE-OF-SPRINT, COMPLETE % WILL BE CALCULATED BASE ON LATEST TICKET STATUS, NOT LAST-DAY-OF-SPRINT TICKET STATUS
IF NOT exists(SELECT date FROM hm_ticket_history WHERE ticket = v_ticket AND cast(date AS DATE) = v_current_date)
then
SELECT CASE WHEN (position(upper(trim(status)) IN upper(trim(v_sprint_setting))) = 0)
THEN CASE WHEN v_remaining_estimate = 0 AND v_time_logged_tk <> 0 THEN 80
WHEN v_remaining_estimate = 0 AND v_time_logged_tk = 0 THEN 0
WHEN (v_remaining_estimate + v_time_logged_tk) = 0 THEN 0
ELSE round(cast(v_time_spent_second * 100 / (v_time_logged_tk + v_remaining_estimate) AS NUMERIC), 2)
END
ELSE 100
END AS complete
INTO v_complete_tk
FROM hm_ticket
WHERE id = v_ticket;
else
SELECT CASE WHEN (position(upper(trim(status)) IN upper(trim(v_sprint_setting))) = 0)
THEN CASE WHEN v_remaining_estimate = 0 AND v_time_logged_tk <> 0 THEN 80
WHEN v_remaining_estimate = 0 AND v_time_logged_tk = 0 THEN 0
WHEN (v_remaining_estimate + v_time_logged_tk) = 0 THEN 0
ELSE round(cast(v_time_spent_second * 100 / (v_time_logged_tk + v_remaining_estimate) AS NUMERIC), 2)
END
ELSE 100
END AS complete
INTO v_complete_tk
FROM hm_ticket_history
WHERE ticket = v_ticket order by date desc limit 1;
END IF;
END IF;
if v_complete_tk > 100 then v_complete_tk := 100;
end if;
raise notice 'v_sprint_setting: %', v_sprint_setting;
raise notice 'v_complete_tk: %', v_complete_tk;
raise notice '---------------------------------';
-- check has log
IF exists(SELECT id
FROM hm_worklog
WHERE cast(started AS DATE) = cast(v_current_date AS DATE) AND ticket = v_ticket)
THEN
v_has_log := 1;
ELSE
v_has_log := 0;
END IF;
--raise notice 'v_has_log: %', v_has_log;
-- calculate oe of sprint
SELECT sum(x.oe)
INTO v_oe_sprint
FROM
(
SELECT CASE WHEN coalesce(original_estimate, 0) = 0
THEN coalesce(time_logged, 0)
ELSE coalesce(original_estimate, 0)
END oe
FROM hm_ticket
WHERE sprint = v_sprint_id AND cast(first_activity_date AS DATE) <= v_current_date
AND has_past_sprint = 0
UNION ALL
SELECT CASE WHEN coalesce(b.original_estimate, 0) = 0
THEN coalesce(a.time_logged - b.time_logged)
ELSE coalesce(b.original_estimate, 0)
END oe
FROM hm_ticket a, hm_ticket_past_sprint b
WHERE a.id = b.ticket AND a.sprint = v_sprint_id AND cast(a.first_activity_date AS DATE) <= v_current_date
AND a.has_past_sprint = 1
) x;
-- raise notice 'v_oe_sprint: %', v_oe_sprint;
-- calculate v_oe_tk_burnt
SELECT CASE WHEN v_time_spent_second = 0 OR v_oe_tk = 0
THEN 0
ELSE round(cast((v_time_spent_second * 100 / v_oe_tk) AS NUMERIC), 2)
END
INTO v_oe_tk_burnt;
--raise notice 'v_oe_tk_burnt: %', v_oe_tk_burnt;
-- calculate v_oe_sprint_burnt
IF v_oe_sprint = 0
THEN
v_oe_sprint_burnt:=100;
ELSE
SELECT round(cast((v_time_spent_second * 100 / v_oe_sprint) AS NUMERIC), 2)
INTO v_oe_sprint_burnt;
END IF;
--raise notice 'v_oe_sprint_burnt: %', v_oe_sprint_burnt;
-- calculate v_project_complete
IF v_oe_sprint = 0
THEN
v_project_complete:=100;
ELSE
SELECT round(cast((v_complete_tk * v_oe_tk / v_oe_sprint) AS NUMERIC), 2)
INTO v_project_complete;
END IF;
-- raise notice 'v_project_complete: %', v_project_complete;
IF v_current_date >= v_first_activity_date
THEN
INSERT INTO hm_ticket_statistic (complete, date, has_log, last_modified, original_estimate_burnt, original_estimate_project_burnt, project_complete, status, ticket, sprint)
VALUES
(v_complete_tk, cast(v_current_date AS DATE), v_has_log, current_timestamp, v_oe_tk_burnt, v_oe_sprint_burnt,
v_project_complete, 1, v_ticket, v_sprint_id)
ON CONFLICT (date, ticket, sprint)
DO UPDATE
SET complete = v_complete_tk,
has_log = v_has_log,
original_estimate_burnt = v_oe_tk_burnt,
original_estimate_project_burnt = v_oe_sprint_burnt,
project_complete = v_project_complete;
END IF;
v_current_date:= v_current_date + INTERVAL '24 hours';
EXIT WHEN NOT found;
END LOOP;
END LOOP;
CLOSE rl_cursor;
RETURN 0;
END;
这是存储过程
{{1}}
此外,如果您在代码中看到任何可以改进的内容,请建议我。
答案 0 :(得分:3)
恢复转储后,尝试在本地数据库上运行analyze
。这会更新统计信息。
答案 1 :(得分:0)
终于发现了这个bug。这是一个死锁bug,我在功能方面使用了Synchronized太多了,它们开始卡住了。生产服务器仍然遇到同样的问题,我只是没有看到它。所以我尝试更有选择地使用Synchronized,减少Synchronized on上的函数的大小。然后就修好了。