可以在postgresql中保留最大记录数吗?


9

基本上,我们的Postgresql表的一部分用于保存服务器访问日志,因此有时在生产过程中,这可能会变得很大。有什么办法在postgresql中设置为具有一个表可以拥有的最大记录数并推出最旧的记录?

Answers:


12

您可以定义一个触发器来保持所需的行号:

CREATE OR REPLACE FUNCTION trf_keep_row_number_steady()
RETURNS TRIGGER AS
$body$
BEGIN
    -- delete only where are too many rows
    IF (SELECT count(id) FROM log_table) > rownum_limit
    THEN 
        -- I assume here that id is an auto-incremented value in log_table
        DELETE FROM log_table
        WHERE id = (SELECT min(id) FROM log_table);
    END IF;
END;
$body$
LANGUAGE plpgsql;

CREATE TRIGGER tr_keep_row_number_steady 
AFTER INSERT ON log_table
FOR EACH ROW EXECUTE PROCEDURE trf_keep_row_number_steady();

这可能不是最佳性能的选择,但是一旦达到极限,就永远不会超过它。如果有波动的空间,则可以定期检查行号,并从头开始删除多余的行。

编辑: 如果您的日志非常大(例如每月一百万),那么比分区可能是最简单的解决方案。然后,您可以简单地删除不必要的表(例如,在何处max(timestamp) < CURRENT_DATE - 1 year)。您可以将时间戳(或派生日期)用作范围分区的条件。

但是在丢弃旧日志之前要小心。您确定您将永远不需要那些吗?


我们可以定期执行它,并且我们确定一旦表足够大时我们将不再需要它们,我只是想尽可能地自动化DB维护:)
Jharwood 2012年

我也希望postgres可以告诉自己哪个年龄较大,但如果没有,则可以使用我们创建的时间戳字段“ 2012-06-22 17:17:52.692514”
Jharwood 2012年

@Jharwood-编辑了我的答案。如果您需要更多详细信息,请告诉我。
dezso 2012年

2
对分区建议+1。如果要进行计数而没有每次扫描表的极高开销,则可以使用pg_class.reltuples进行近似计算,也可以使用触发器来维护“控制”表中的计数。
kgrittn

4

我创建了一个更通用的表无关功能。

CREATE OR REPLACE FUNCTION keep_row_number_steady()
RETURNS TRIGGER AS
$body$
DECLARE
    tab text;
    keyfld text;
    nritems INTEGER;
    rnd DOUBLE PRECISION;
BEGIN
    tab := TG_ARGV[0];
    keyfld := TG_ARGV[1];
    nritems := TG_ARGV[2]; 
    rnd := TG_ARGV[3];

    IF random() < rnd
    THEN 
        EXECUTE(format('DELETE FROM %s WHERE %s < (SELECT %s FROM %s ORDER BY %s DESC LIMIT 1 OFFSET %s)', tab, keyfld, keyfld, tab, keyfld, nritems));
    END IF;
    RETURN NULL;
END;
$body$
LANGUAGE plpgsql;

CREATE TRIGGER log_table_keep_row_number_steady_trigger
AFTER INSERT ON log_table
FOR EACH STATEMENT EXECUTE PROCEDURE keep_row_number_steady('log_table', 'id', 1000, 0.1);

该函数采用4个参数:

  • 标签:表名
  • keyfld:数字式,渐进式键字段
  • 说明:要保留的项目数
  • rnd:随机数,从0到1;它越大,清理表的频率就越高(0 =从不,1 =总是,0.1 = 10%的时间)

这样,您可以创建要调用同一函数的触发器数量。

希望这可以帮助。


0

我创建了此proc并从PG Agent(或Windows作业或cron作业)运行它。我可以有更多的行,这只会使我的日志表不会太大。节省触发器的开销。

CREATE or replace FUNCTION activitylogcleanup(_MaxRows int) RETURNS void
    LANGUAGE plpgsql
    AS $$
DECLARE
   minid    int;
BEGIN
    SELECT logid into minid FROM activitylogapplication 
     order by logid desc limit 1 OFFSET _MaxRows;

    if not found then 
        return;
    END IF; 

    Delete from activitylogapplication where logid < minid;
END;
$$;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.