Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql 为大量记录运行函数需要花费很长时间_Postgresql_Function_Concurrency_Sql Update_Plpgsql - Fatal编程技术网

Postgresql 为大量记录运行函数需要花费很长时间

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 =

我在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 = '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
    /
    LIMIT 1
    I。也可以使用索引

  • 如果表很大,则至少需要在
    id
    上建立索引。假设
    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
    /
    LIMIT 1
    I。也可以使用索引

  • 如果表很大,则至少需要在
    id
    上建立索引。假设
    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
    /
    LIMIT 1
    I。也可以使用索引

  • 如果表很大,则至少需要在
    id
    上建立索引。假设
    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
    要好得多