Postgres内存不足,触发器

时间:2017-03-22 06:54:31

标签: postgresql triggers postgis

我有两张桌子:

CREATE TABLE foo (
    id serial primary key,
    abc text
);

CREATE TABLE bar (
    id serial primary key,
    xyz text
);

我在表foo上有一个触发器:

CREATE FUNCTION foo_before_insert()
    RETURNS trigger AS
    $BODY$
        BEGIN

        INSERT INTO bar (id, xyz)
        VALUES (
            NEW.id,
            FooFunction(NEW.abc)
        );

        RETURN NEW;

        END;
    $BODY$

    LANGUAGE plpgsql VOLATILE
    COST 100;

CREATE TRIGGER foo_before_insert
    BEFORE INSERT ON foo
    EXECUTE PROCEDURE foo_before_insert();

因此,当某些内容插入foo时,某些内容也会插入barabc列会被FooFunction操纵。这是简化版。

真实世界FooFunction获取经度和纬度的两个数字参数,for loop SELECT查询选择单个几何列,是否使用几何列执行一些Postgis函数和输入,并返回一个布尔值。基本上,该函数试图确定一个点是否位于一组多边形中的至少一个多边形内。

这里有功能的肉和土豆:

    FOR currentLinestring IN
        SELECT linestring
        FROM   bla
        WHERE  yadda yadda...
    LOOP
        currentLinestring = ST_MakeLine(currentLinestring);

        -- Can't make polygon with under 4 points
        IF ST_NPoints(currentLinestring) < 4 THEN
            EXIT;
        END IF;

        IF ST_Contains(ST_MakePolygon(currentLinestring), ST_SetSRID(ST_MakePoint(_lon, _lat), 4326)) = TRUE THEN
            -- Is not out of bounds
            RETURN FALSE;
        END IF;
    END LOOP;

    -- Is out of bounds
    RETURN TRUE;

捕获是在触发器外部(如质量更新)时功能100%正常但在触发器功能内部时,Postgres的内存使用量会攀升并攀升,直到所有内存耗尽并且Postgres崩溃。当我COPY使用可能有10万行的大型CSV时,会发生这种情况。

造成这种情况的原因是什么?我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

第一个重要的问题是,如果事务提交后内存被释放(尝试使用较小的CSV文件)。如果情况并非如此,则会使问题更严重。

接下来要检查的是PostgreSQL服务器日志中的内存转储,看起来有点像这样:

TopMemoryContext: 221952 total in 17 blocks; 7440 free (41 chunks); 214512 used
   TopTransactionContext: 8192 total in 1 blocks; 6384 free (0 chunks); 1808 used
     CurTransactionContext: 0 total in 0 blocks; 0 free (0 chunks); 0 used
   Type information cache: 24240 total in 2 blocks; 3744 free (0 chunks); 20496 used
   RI compare cache: 24576 total in 2 blocks; 15984 free (5 chunks); 8592 used
...

查看哪个内存上下文包含所有内存。

您应该确保最近修补了PostgreSQL和PostGIS。

有可能内存在某些PostGIS功能中泄露。 尝试通过消除一些功能尽可能地缩小范围,直到你知道哪一个是罪魁祸首。

然后创建一个简单的测试用例,让人们重现问题并将问题报告给PostGIS(如果你可以在没有PostGIS的情况下重现问题,则报告PostgreSQL),包括你的所有发现(内存环境......)。

如果您无法解决此问题,这是解决此问题的最佳方法,例如将工作分成多个交易。