循环中的PostgreSQL DROP TABLE失败,出现ERROR:共享内存

时间:2017-04-27 20:44:05

标签: postgresql locking out-of-memory plpgsql

我有一个数据库,结构上有很多(3000+)架构。我正在尝试从每个架构中删除两个表。所以我编写了一个循环遍历模式并尝试删除这些表的函数。

当我执行我的函数时,我得到了ERROR:共享内存中没有表被删除。

是否有可能强制PostgreSQL批量提交drop table语句?

这是我的功能(简化为相关问题):

CREATE OR REPLACE FUNCTION utils.drop_webstat_from_schema(schema_name character varying default '')
  RETURNS SETOF record AS
$BODY$
declare
    s record;
    sql text;
BEGIN
    for s in 
        select distinct t.table_schema from information_schema.tables t
        where 
                schema_name <> '' and t.table_schema = schema_name 
                or 
                schema_name = '' and t.table_schema like 'myprefix_%'
    loop
        sql := 'DROP TABLE IF EXISTS ' || s.table_schema || '.webstat_hit, ' || s.table_schema || '.webstat_visit';
        execute sql;
        raise info '%; -- OK', sql;
        return next s;
    end loop;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  ROWS 1000;

正如您所看到的,该函数循环遍历模式集,并且对于每个模式,构造并执行以下SQL。

DROP TABLE IF EXISTS <schema_name>.webstat_hit, <schema_name>.webstat_visit

我猜PostgreSQL试图在丢弃之前锁定所有这些表,并且它达到了最大配置限制。 可能如果我将 max_locks_per_transaction 增加到某个固定数字,我可能会设法锁定所有表并删除它们。

但是我正在寻找一种解决方案,它会逐步删除表并仅锁定步骤中的那些表。与每10个模式一样,锁定和删除批处理。

我可以在PostgreSQL中这样做,如果是这样,怎么样?谢谢。

1 个答案:

答案 0 :(得分:1)

我从drop函数中取出模式循环。

因此,假设fn_drop plpgsql循环模式并调用for i in $(psql -c "select nspname form pg_namespaces where blah blah"); do psql -c "drop damn table"; done; 。如果通过dblink执行t=# do $$ declare _t text; begin for _r in 1..2 loop select t into _t from dblink('dbname=t'::text,'select now()::text'::text) rtn (t text); raise info '%',concat('local: ',now(),', dblink: ',_t); end loop; end; $$ ; INFO: local: 2017-04-28 07:38:11.352026+00, dblink: 2017-04-28 07:38:11.355149+00 INFO: local: 2017-04-28 07:38:11.352026+00, dblink: 2017-04-28 07:38:11.358211+00 DO Time: 6.811 ms ,则可以在plpgsql中批量提交。

另一种在模式之间进行提交的方法,在bash中循环,例如:

{{1}}

使用dblink在不同事务中进行本地调用的示例(在同一数据库中注意now()的差异):

{{1}}