我们有一个多线程应用程序使用的 postgreql 连接池,它将一些记录永久地插入到大表中。所以,假设我们有 10 个数据库连接,执行相同的功能,插入记录。
问题是,我们插入了 10 条记录,同时它应该只插入 2-3 条记录,如果只有事务可以看到彼此的记录(我们的函数根据日期决定不插入记录找到的最后一条记录)。
我们不能承受函数执行期间的表锁定。我们尝试了不同的技术来使数据库立即将我们的规则应用于新记录,尽管它们是在并行事务中创建的,但还没有成功。
因此,我将非常感谢任何帮助或想法!
更具体地说,这里是代码:
schm.events ( evtime TIMESTAMP, ref_id INTEGER, param INTEGER, type INTEGER);
记录过滤规则:
BEGIN
select count(*) into nCnt
from events e
where e.ref_id = ref_id and e.param = param and e.type = type
and e.evtime between (evtime - interval '10 seconds') and (evtime + interval '10 seconds')
if nCnt = 0 then
insert into schm.events values (evtime, ref_id, param, type);
end if;
END;
更新(不幸的是,评论长度不够)
我已将唯一索引解决方案应用于生产。结果还算可以接受,但最初的目标还没有实现。问题是,使用唯一哈希,我无法控制具有顺序 hash_codes 的 2 条记录之间的间隔。
这是代码:
CREATE TABLE schm.events_hash (
hash_code bigint NOT NULL
);
CREATE UNIQUE INDEX ui_events_hash_hash_code ON its.events_hash
USING btree (hash_code);
--generate the hash codes data by partioning(splitting) evtime in 10 sec intervals:
INSERT into schm.events_hash
select distinct ( cast( trunc( extract(epoch from evtime) / 10 ) || cast( ref_id as TEXT) || cast( type as TEXT ) || cast( param as TEXT ) as bigint) )
from schm.events;
--and then in a concurrently executed function I insert sequentially:
begin
INSERT into schm.events_hash values ( cast( trunc( extract(epoch from evtime) / 10 ) || cast( ref_id as TEXT) || cast( type as TEXT ) || cast( param as TEXT ) as bigint) );
insert into schm.events values (evtime, ref_id, param, type);
end;
在这种情况下,如果 evtime 位于哈希确定的时间间隔内,则只插入一条记录。情况是,我们可以跳过引用不同确定间隔但彼此接近(小于 60 秒间隔)的记录。
insert into schm.events values ( '2013-07-22 19:32:37', '123', '10', '20' ); --inserted, test ok, (trunc( extract(epoch from cast('2013-07-22 19:32:37' as timestamp)) / 10 ) = 137450715 )
insert into schm.events values ( '2013-07-22 19:32:39', '123', '10', '20' ); --filtered out, test ok, (trunc( extract(epoch from cast('2013-07-22 19:32:39' as timestamp)) / 10 ) = 137450715 )
insert into schm.events values ( '2013-07-22 19:32:41', '123', '10', '20' ); --inserted, test fail, (trunc( extract(epoch from cast('2013-07-22 19:32:41' as timestamp)) / 10 ) = 137450716 )
我想一定有办法修改hash函数来达到最初的目标,但是还没有找到。也许,有一些表约束表达式,由 postgresql 本身在事务之外执行?