Postgresql 为大量记录运行函数需要花费很长时间
我在Postgres 9.3.5中创建了以下函数:Postgresql 为大量记录运行函数需要花费很长时间,postgresql,function,concurrency,sql-update,plpgsql,Postgresql,Function,Concurrency,Sql Update,Plpgsql,我在Postgres 9.3.5中创建了以下函数: CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text) RETURNS text AS $BODY $Declare result text; BEGIN select min(id) into result from table where id_used is null and id_type = val2; update table set id_used =
CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text)
RETURNS text AS
$BODY
$Declare
result text;
BEGIN
select min(id) into result from table
where id_used is null and id_type = val2;
update table set
id_used = 'Y',
col1 = val1,
id_used_date = now()
where id_type = val2
and id = result;
RETURN result;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
当我在一个包含1000条或更多记录的循环中运行这个函数时,它只是执行冻结操作,并且只说“查询正在运行”。当我检查我的表格时,没有任何内容被更新。当我运行一个或两个记录时,它运行良好
运行时的函数示例:
select get_result('123','idtype');
表列:
id character varying(200),
col1 character varying(200),
id_used character varying(1),
id_used_date timestamp without time zone,
id_type character(200)
id
是表索引
有人能帮你吗?你很可能正处于比赛状态。当您在单独的事务中连续快速运行函数1000次时,会发生如下情况:
T1 T2 T3 ...
SELECT max(id) -- id 1
SELECT max(id) -- id 1
SELECT max(id) -- id 1
...
Row id 1 locked, wait ...
Row id 1 locked, wait ...
UPDATE id 1
...
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
...
大量重写并简化为SQL函数:
CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text)
RETURNS text AS
$func$
UPDATE table t
SET id_used = 'Y'
, col1 = val1
, id_used_date = now()
FROM (
SELECT id
FROM table
WHERE id_used IS NULL
AND id_type = val2
ORDER BY id
LIMIT 1
FOR UPDATE -- lock to avoid race condition! see below ...
) t1
WHERE t.id_type = val2
-- AND t.id_used IS NULL -- repeat condition (not if row is locked)
AND t.id = t1.id
RETURNING id;
$func$ LANGUAGE sql;
有更多解释的相关问题:
- 不要运行两个单独的SQL语句。这样做成本更高,并且扩大了比赛条件的时限。一个带有子查询的
要好得多UPDATE
- 简单的任务不需要PL/pgSQL。您仍然可以使用PL/pgSQL,更新保持不变
- 您需要锁定所选行以抵御竞争条件。但你不能用你领导的聚合函数来做这件事,因为:
- 我的。幸运的是,您可以轻松地将
替换为上面提供的等效min(id)
/ORDER BY
I。也可以使用索引LIMIT 1
- 如果表很大,则至少需要在
上建立索引。假设id
已被索引为id
主键,这将有所帮助。但这一额外措施可能会有更大的帮助:
T1 T2 T3 ...
SELECT max(id) -- id 1
SELECT max(id) -- id 1
SELECT max(id) -- id 1
...
Row id 1 locked, wait ...
Row id 1 locked, wait ...
UPDATE id 1
...
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
...
大量重写并简化为SQL函数:
CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text)
RETURNS text AS
$func$
UPDATE table t
SET id_used = 'Y'
, col1 = val1
, id_used_date = now()
FROM (
SELECT id
FROM table
WHERE id_used IS NULL
AND id_type = val2
ORDER BY id
LIMIT 1
FOR UPDATE -- lock to avoid race condition! see below ...
) t1
WHERE t.id_type = val2
-- AND t.id_used IS NULL -- repeat condition (not if row is locked)
AND t.id = t1.id
RETURNING id;
$func$ LANGUAGE sql;
有更多解释的相关问题:
- 不要运行两个单独的SQL语句。这样做成本更高,并且扩大了比赛条件的时限。一个带有子查询的
要好得多UPDATE
- 简单的任务不需要PL/pgSQL。您仍然可以使用PL/pgSQL,更新保持不变
- 您需要锁定所选行以抵御竞争条件。但你不能用你领导的聚合函数来做这件事,因为:
- 我的。幸运的是,您可以轻松地将
替换为上面提供的等效min(id)
/ORDER BY
I。也可以使用索引LIMIT 1
- 如果表很大,则至少需要在
上建立索引。假设id
已被索引为id
主键,这将有所帮助。但这一额外措施可能会有更大的帮助:
T1 T2 T3 ...
SELECT max(id) -- id 1
SELECT max(id) -- id 1
SELECT max(id) -- id 1
...
Row id 1 locked, wait ...
Row id 1 locked, wait ...
UPDATE id 1
...
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
...
大量重写并简化为SQL函数:
CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text)
RETURNS text AS
$func$
UPDATE table t
SET id_used = 'Y'
, col1 = val1
, id_used_date = now()
FROM (
SELECT id
FROM table
WHERE id_used IS NULL
AND id_type = val2
ORDER BY id
LIMIT 1
FOR UPDATE -- lock to avoid race condition! see below ...
) t1
WHERE t.id_type = val2
-- AND t.id_used IS NULL -- repeat condition (not if row is locked)
AND t.id = t1.id
RETURNING id;
$func$ LANGUAGE sql;
有更多解释的相关问题:
- 不要运行两个单独的SQL语句。这样做成本更高,并且扩大了比赛条件的时限。一个带有子查询的
要好得多UPDATE
- 简单的任务不需要PL/pgSQL。您仍然可以使用PL/pgSQL,更新保持不变
- 您需要锁定所选行以抵御竞争条件。但你不能用你领导的聚合函数来做这件事,因为:
- 我的。幸运的是,您可以轻松地将
替换为上面提供的等效min(id)
/ORDER BY
I。也可以使用索引LIMIT 1
- 如果表很大,则至少需要在
上建立索引。假设id
已被索引为id
主键,这将有所帮助。但这一额外措施可能会有更大的帮助:
T1 T2 T3 ...
SELECT max(id) -- id 1
SELECT max(id) -- id 1
SELECT max(id) -- id 1
...
Row id 1 locked, wait ...
Row id 1 locked, wait ...
UPDATE id 1
...
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
Wake up, UPDATE id 1 again!
COMMIT
...
大量重写并简化为SQL函数:
CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text)
RETURNS text AS
$func$
UPDATE table t
SET id_used = 'Y'
, col1 = val1
, id_used_date = now()
FROM (
SELECT id
FROM table
WHERE id_used IS NULL
AND id_type = val2
ORDER BY id
LIMIT 1
FOR UPDATE -- lock to avoid race condition! see below ...
) t1
WHERE t.id_type = val2
-- AND t.id_used IS NULL -- repeat condition (not if row is locked)
AND t.id = t1.id
RETURNING id;
$func$ LANGUAGE sql;
有更多解释的相关问题:
- 不要运行两个单独的SQL语句。这样做成本更高,并且扩大了比赛条件的时限。一个带有子查询的
要好得多UPDATE
- 你