我有一个执行复杂负载平衡的功能,我需要首先找出空闲服务器的列表。之后,我必须遍历该列表的一个子集,最后我必须做很多复杂的事情,所以我不想一遍又一遍地不断查询该列表。参见以下示例(请注意,这仅是PSUEDO CODE)。
CREATE OR REPLACE FUNCTION load_balance (p_company_id BIGINT, p_num_min_idle_servers BIGINT)
RETURNS VOID
AS $$
DECLARE
v_idle_server_ids BIGINT [];
v_num_idle_servers BIGINT;
v_num_idle_servers_to_retire BIGINT;
BEGIN
PERFORM * FROM server FOR UPDATE;
SELECT
count(server.id)
INTO
v_num_idle_servers
WHERE
server.company_id=p_company_id
AND
server.connection_count=0
AND
server.state = 'up';
v_num_idle_servers_to_retire = v_num_idle_servers - p_num_min_idle_servers;
SELECT
server.id
INTO
v_idle_server_ids
WHERE
server.company_id=p_company_id
AND
server.connection_count=0
AND
server.state = 'up'
ORDER BY
server.id;
FOR i in 1..v_num_idle_servers_to_retire
UPDATE
server
SET
state = 'down'
WHERE
server.id = v_idle_server_ids[i];
问题:我当时正在考虑获取服务器列表,并逐一遍历它们。在postgres中有可能吗?
注意:我尝试将所有内容放在一个查询中,但是由于存在多个联接和子查询,因此非常非常复杂。例如,一个系统在三个不同的服务器上运行着三个应用程序,这些应用程序知道它们的负载,但是服务器知道它们的公司隶属关系,因此我需要将系统加入到应用程序中,并将应用程序加入到服务器中
答案 0 :(得分:1)
经验法则:如果您使用SQL循环,则可能是更好的方法。
您要set state = 'down'
直到拥有一定数量的空闲服务器。
我们可以在一个语句中完成此操作。使用Common Table Expression查询您的空闲服务器,并将其提供给update from
。如果您经常这样做,则可以将CTE转换为视图。
但是我们需要根据有多少个空闲服务器来限制拆卸的数量。我们可以做到这一点。但是update from
没有限制,因此我们需要第二个CTE来限制结果。
在这里,我已经硬编码了company_id 1和p_num_min_idle_servers 2。
with idle_servers as (
select id
from server
where server.company_id=1
and connection_count=0
and state = 'up'
),
idle_servers_to_take_down as (
select id
from idle_servers
-- limit doesn't work in update from
limit (select count(*) - 2 from idle_servers)
)
update server
set state = 'down'
from idle_servers_to_take_down
where server.id = idle_servers_to_take_down.id
这样做的好处是,只需执行一条语句即可避免争用情况,而不必锁定整个表。