Answers:
您可以定义一个触发器来保持所需的行号:
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
)。您可以将时间戳(或派生日期)用作范围分区的条件。
但是在丢弃旧日志之前要小心。您确定您将永远不需要那些吗?
我创建了一个更通用的表无关功能。
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个参数:
这样,您可以创建要调用同一函数的触发器数量。
希望这可以帮助。
我创建了此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;
$$;