Sql 多进程写入的事务封装

Sql 多进程写入的事务封装,sql,transactions,acid,Sql,Transactions,Acid,我有一个数据库场景(我使用的是Oracle),在这个场景中,几个进程向一个表中插入数据,一个进程从中进行选择。该表基本上用作中间存储器,多个进程(以下称为writer)向其中写入日志事件,单个进程(以下称为Reader)从中读取事件以供进一步处理。读取器必须读取插入表中的所有事件 目前,这是通过从升序序列中为每个插入的记录分配一个id来完成的。读取器周期性地从表中选择一个条目块,其中id大于先前读取的块的最大id。例如,类似于: SELECT * FROM TRANSACTION_LOG

我有一个数据库场景(我使用的是Oracle),在这个场景中,几个进程向一个表中插入数据,一个进程从中进行选择。该表基本上用作中间存储器,多个进程(以下称为writer)向其中写入日志事件,单个进程(以下称为Reader)从中读取事件以供进一步处理。读取器必须读取插入表中的所有事件

目前,这是通过从升序序列中为每个插入的记录分配一个id来完成的。读取器周期性地从表中选择一个条目块,其中id大于先前读取的块的最大id。例如,类似于:

SELECT
  *
FROM
  TRANSACTION_LOG
WHERE
  id > (
    SELECT
      last_id
    FROM
      READER_STATUS
   );
这种方法的问题在于,由于写入程序是并发操作的,所以行并不总是按照其分配的id的顺序插入,即使这些行是按升序顺序分配的。也就是说,有时在id=110的记录之后写入id=100的行,因为写入id=110的行的过程是在写入id=100的记录的过程之后开始的,但首先提交。如果读卡器已经读取了id=110的行,则这可能导致读卡器丢失id=100的行

强制写入程序在表上使用独占锁将解决问题,因为这将强制写入程序按顺序插入,并且使读取器等待任何未完成的提交。然而,这可能不会很快

我的想法是,读者在阅读之前,只要等待任何优秀作家的作品就足够了。也就是说,编写器可以继续与读者阅读一样长的时间并发操作,直到所有编写器都完成为止

我的问题是:

如何指示我的读卡器进程等待我的写卡器进程的任何未完成提交?对于上述问题,我们也欢迎提出任何其他建议

有趣的问题。听起来您正在构建一个不错的解决方案。
我希望我能帮忙

一些建议

作者身份 您可以创建一个名为WRITER_STATUS的表,该表有一个last_id字段:每个WRITER在使用要写入日志的id写入之前更新该表,但前提是其id大于last_id的当前值

读者还检查了这个表,现在知道是否有作者还没有写过

读卡器日志 这可能更有效。
读卡器读取后,会检查检索到的记录中是否有漏洞。
然后,它将任何缺少的ID记录到缺少的_id表中,并在下次读取时执行如下操作

SELECT *
FROM   TRANSACTION_LOG
WHERE  id > (SELECT last_id
             FROM   READER_STATUS)
OR     id IN ( SELECT id from MISSING_IDS ) 

您可能希望在读卡器进程中对表设置独占锁。这将等待所有写入程序完成并释放其行锁,因此您可以确保没有未完成的写入程序事务。

我不会执行任何锁定,这会干扰并发性和吞吐量

如果逐行跟踪已处理的日志行,则也不需要Reader_Status表

我要做的是:在日志表中添加一个新列。例如,将其称为“已处理”。将其设置为布尔值,默认值为false(或小整数,默认值为0或其他值)。写入程序在插入时使用默认值

当读取器查询下一个要处理的记录块时,他会查询处理为false且id值较低的行

SELECT * FROM Transaction_Log
WHERE processed = 0
ORDER BY id
LIMIT 10;
在处理它们时,读者使用UPDATE将processed从false更改为true。因此,下次读者查询记录块时,他肯定不会得到他已经处理过的行

UPDATE Transaction_Log
SET processed = 1
WHERE id = ?;  -- do this for each row processed
此更新不应与写入程序执行的插入操作冲突


如果其他写入程序未按顺序提交任何行,读者将在下次查询时看到这些行,前提是他总是按照id列从最低值到最高值的顺序处理这些行。

因为您知道读取器处理的最后一个id,所以您可以通过以下方式请求下一个工作项:

select * from Transaction_log where id = (
  select last_id + 1 /* or whatever increment your sequencer has */
    from Reader_status)

我同意AJ的解决方案()。此外,以下建议可能有助于减少孔的数量

1) 使用
Oracle序列
创建id,并使用
auto increment
如下所示

INSERT INTO transaction_table VALUES(id__seq.nextval, <other columns>);
插入事务表值(id_useq.nextval,);
2) 使用
autoCommit(true)
以便insert将立即提交


这两个步骤将大大减少孔的数量。仍然有可能是一些插入先开始,但后来提交,其间发生了读取操作。

谢谢。当然值得考虑。在接下来的几天里,我会尝试各种各样的东西。酷。请更新您的问题,让我们知道您进展如何(或者更好,发布答案)。这是偶尔出现的问题之一,一个很好的解决办法就是金粉!祝你好运。是的,我担心这会让读者等待。问题是,它会对性能造成什么影响。这取决于读卡器进程运行的频率和时间。此解决方案至少允许多个写入程序并行运行,因此,如果写入的次数明显增加,那么读取性能影响应该是可以承受的。