PostgreSQL function card in the For loop

The function was stuck before the loop.

select * from scm_main.fn_connection_stations(1219646)

Print the message “Start…” but not the message “…End”.

CREATE OR REPLACE FUNCTION 
scm_main.fn_connection_stations(var_connection_id bigint)
RETURNS SETOF scm_main.typ_connection_stations AS
$BODY$DECLARE
var_affected INTEGER DEFAULT 0;
var_row scm_main.typ_connection_stations%ROWTYPE;
BEGIN
RAISE NOTICE'Start.. .';
FOR var_row IN
SELECT DISTINCT v.vbvdata_station_id
FROM scm_main.tbl_vbvdata AS v
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id =
p.packet_id and p.packet_connection_id = var_connection_id)
--WHERE v.vbvdata_packet_id IN
--( SELECT packet_id FROM scm_main.tbl_packet AS o_p WHERE
o_p.packet_connection_id = var_connection_id)
LOOP
RETURN NEXT var_row;
END LOOP;
RAISE NOTICE'...End';
RETURN;
END
$BODY$
LANGUAGE plpgsql STABLE STRICT
COST 100< br /> ROWS 1000;
ALTER FUNCTION scm_main.fn_connection_stations(bigint)
OWNER TO postgres;

The query itself is very simple and runs when it is called directly, as shown below:< /p>

SELECT DISTINCT v.vbvdata_station_id 
FROM scm_main.tbl_vbvdata AS v
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id =
p .packet_id and p.packet_connection_id = 1219646)

I think the problem must be the locking of the table. But I absolutely don’t understand the reason and the problem that can be solved.

Some time ago, the comment section It was working. But after a while, the same problem appeared. I solved it by changing the query and replacing the condition with inner joins (cascading queries). But none of them worked this time!

Update

I made it work again with a stupid change:

INNER JOIN scm_main.tbl_packet AS p ON (v .vbvdata_packet_id = p.packet_id 
and p.packet_connection_id = var_connection_id)`

Change to:

INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id)
where p.packet_connection_id in (select var_connection_id)

and works very well.

Another interesting point is that even The following changes did not work and still hang:

INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id) 
where p .packet_connection_id = var_connection_id

Now I found the solution. But I want to know how it happened!

If this surface change to the query is used to fix it, then it may not “stuck “Live”, but run very slowly due to improper selection of the execution plan.

The fact that the performance of the query in the function is worse than itself may be the result of plan caching. Basically, Postgres may try to avoid the cost of replanning the query execution plan by creating and reusing generics (that is, parameter independence). Unfortunately, these general plans may be far from optimal.

A possibility for bad plans The interpretation is bad statistics; if Postgres doesn’t have accurate information about the data, then bad decisions are bound to be made. It may be helpful to analyze the tables involved, but it is usually not necessary to do this-autovacuum should usually make statistics Keep it up-to-date (assuming you are already running).

A common cause of statistical bias is uneven distribution of values ​​(in your case, if there is a big difference in the number of packets per connection). Using ALTER TABLE ... SET STATISTICS (followed by ANALYZE) to increase the level of detail of the statistics can greatly improve this. In some cases, high values ​​will slow down the plan, but 500 (maybe) It is a safe starting point.

If there is no other work, you can bypass the plan cache by running a query by EXECUTE.

This function is before the loop Is stuck.

select * from scm_main.fn_connection_stations(1219646)

Print the message “Start…” but not the message “…End ”.

CREATE OR REPLACE FUNCTION 
scm_main.fn_connection_stations(var_connection_id bigint)
RETURNS SETOF scm_main.typ_connection_stations AS
$BODY$DECLARE < br /> var_affected INTEGER DEFAULT 0;
var_row scm_mai n.typ_connection_stations%ROWTYPE;
BEGIN
RAISE NOTICE'Start...';
FOR var_row IN
SELECT DISTINCT v.vbvdata_station_id
FROM scm_main.tbl_vbvdata AS v
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id =
p.packet_id and p.packet_connection_id = var_connection_id)
--WHERE v.vbvdata_packet_id IN
--( SELECT packet_id FROM scm_main.tbl_packet AS o_p WHERE
o_p.packet_connection_id = var_connection_id)
LOOP
RETURN NEXT var_row;
END LOOP;
RAISE NOTICE'...End' ;
RETURN;
END
$BODY$
LANGUAGE plpgsql STABLE STRICT
COST 100
ROWS 1000;
ALTER FUNCTION scm_main.fn_connection_stations( bigint)
OWNER TO postgres;

The query itself is very simple and runs when called directly, as shown below:

SELECT DISTINCT v .vbvdata_station_id 
FROM scm_main.tbl_vbvdata AS v
INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id and p.packet_connection_id = 1219646)

I think the problem must be the locking of the table. But I absolutely don’t understand the reason and the problem that can be solved.

The comment section was working some time ago. But after a while, the same problem appeared. I solved it by changing the query and replacing the condition with inner joins (cascading queries). But this time none of them worked!

Update

I made it work again with a stupid change:

INNER JOIN scm_main.tbl_packet AS p ON (v .vbvdata_packet_id = p.packet_id 
and p.packet_connection_id = var_connection_id)`

Change to:

INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id)
where p.packet_connection_id in (select var_connection_id)

and works very well.

Another interesting point is that even The following changes did not work and still hang:

INNER JOIN scm_main.tbl_packet AS p ON (v.vbvdata_packet_id = p.packet_id) 
where p .packet_connection_id = var_connection_id

Now I found the solution. But I want to know how it happened!

If you fix it by this superficial change to the query, then it may not be “stuck”, but due to improper selection of the execution plan Runs very slowly.

The fact that the performance of the query in the function is worse than itself may be the result of plan caching. Basically, Postgres may try to create and reuse generics (i.e. Parameter independent) to avoid the cost of replanning the query execution plan. Unfortunately, these general plans may be far from optimal.

One possible explanation for a bad plan is bad statistics; if Postgres has no data about it If you have accurate information, you are bound to make a bad decision. Analysis of the tables involved may help, but it is usually not necessary-autovacuum should generally keep the statistics up to date (assuming you are already running).

A common cause of statistical deviation is the uneven distribution of values ​​(in your case, if the number of packets per connection is very different). By using ALTER TABLE ... SET STATISTICS< /code>(Followed by ANALYZE) Increasing the level of detail of the statistics can greatly improve this. In some cases, high values ​​will slow down the plan, but 500 (probably) is a safe starting point.

If there is no other work, you can bypass the plan cache by running a query by EXECUTE.

Leave a Comment

Your email address will not be published.