Sql “如何阅读全部”;上次“更改”;火鸟数据库的记录?

Sql “如何阅读全部”;上次“更改”;火鸟数据库的记录?,sql,triggers,firebird,Sql,Triggers,Firebird,我的问题有点棘手,因为它主要是一个逻辑问题。 我试图通过将所有内容读取到内存中来优化我的应用程序速度,但只读取那些记录,这些记录自“上次读取”=上次加载记录的最大时间戳后发生了变化 FirebirdSQL数据库引擎不允许直接更新“After Trigger”中的字段,因此它显然使用“before update or insert”触发器更新字段new.last\u changed=current\u timestamp 问题是: 事实证明,这是一种完全错误的方法,因为这些触发器在事务启动时触发

我的问题有点棘手,因为它主要是一个逻辑问题。
我试图通过将所有内容读取到内存中来优化我的应用程序速度,但只读取那些记录,这些记录自“上次读取”=上次加载记录的最大时间戳后发生了变化

FirebirdSQL数据库引擎不允许直接更新“After Trigger”中的字段,因此它显然使用“before update or insert”触发器更新字段
new.last\u changed=current\u timestamp

问题是: 事实证明,这是一种完全错误的方法,因为这些触发器在事务启动时触发
因此,如果有一个事务比另一个事务花费更多的时间,则保存的“上次更改的时间”将低于触发并在其间完成的短突发事务。
1。tr:13:00:01.400提交。。。每次修改时。
这样我:

  • 不必用日志数据填充数据库
  • 我可以使用
    WHERE last_sequence>1直接查询表
    
  • 无需先预查询“记录器表”
我只是担心:如果事务提交时的
触发器试图更新
最后一个序列
字段,而在触发器锁定(另一个表的)记录之前,第2个事务处于打开状态,会发生什么情况?

这会发生吗

最终解决方案基于以下理念:

  • 插入或更新前每个表的
    触发器可以推送事务的时间:
    RDB$SET_上下文('USER_transaction','table31',current_timestamp
  • 如果接收到这样的上下文,事务提交时的全局
    触发器可以将序列+时间插入“日志记录表”
    
  • 它甚至可以通过只记录“大时差”(如>=1分钟)来处理“夏时制更改”和“间隔”,以减少记录量。)
  • 存储过程可以简化并加快每个查询的“上次查询时间”的计算 例子: 1.)

    (二、三)

    在事务提交位置1上激活提交后创建触发器TRG\u SYNC\u
    声明变量N时间戳;
    声明变量T VARCHAR(255);
    开始
    N=转换(“现在”作为时间戳);
    T=RDB$GET_上下文('USER_TRANSACTION'、'orders_table');
    如果(:T不为空),则开始
    如果(:N<:T),则T=:N--系统时间已更改,例如:夏令时“-1小时
    如果(datediff(从:T到:N的秒数)>60),则--超过1分钟
    插入“同步过去的时间”(ID、表号、训练开始、同步时间、C用户)
    值(GEN_ID(GEN_SYNC_pass_TIMES,1),31,强制转换(:T作为时间戳),:N,当前_用户);
    结束;
    T=RDB$GET_CONTEXT('USER_TRANSACTION','details_table');
    --其他表格。。。
    当有人退出时;
    结束
    
    最终解决方案基于以下理念:

  • 插入或更新前每个表的
    触发器可以推送事务的时间:
    RDB$SET_上下文('USER_transaction','table31',current_timestamp
  • 如果接收到这样的上下文,事务提交时的全局
    触发器可以将序列+时间插入“日志记录表”
  • 它甚至可以通过只记录“大时差”(如>=1分钟)来处理“夏时制更改”和“间隔”,以减少记录量。)
  • 存储过程可以简化并加快每个查询的“上次查询时间”的计算
  • 例子: 1.)

    (二、三)

    在事务提交位置1上激活提交后创建触发器TRG\u SYNC\u
    声明变量N时间戳;
    声明变量T VARCHAR(255);
    开始
    N=转换(“现在”作为时间戳);
    T=RDB$GET_上下文('USER_TRANSACTION'、'orders_table');
    如果(:T不为空),则开始
    如果(:N<:T),则T=:N;--系统时间已更改,例如:夏令时“-1小时
    如果(datediff(从:T到:N的秒数)>60),则——超过1分钟。通过
    插入“同步过去的时间”(ID、表号、训练开始、同步时间、C用户)
    值(GEN_ID(GEN_SYNC_pass_TIMES,1),31,强制转换(:T作为时间戳),:N,当前_用户);
    结束;
    T=RDB$GET_CONTEXT('USER_TRANSACTION','details_table');
    --其他表格。。。
    当有人退出时;
    结束
    
    我想我看到了问题,但你的叙述对我来说有点不清楚。@pilcrow“Edit1”补充道:“你能给我们展示一个非常简单的表,其中包含一些行、你尝试过的触发器以及你想要发生的事情吗?”。用其他词语解释目标。添加了一些代码示例。IMHO由于此问题影响所有行的所有类型的表,因此此问题的示例无法解释任何内容。您可以尝试在提交时使用
    ON COMMIT
    trigger。RAWT方案是每个表触发器记录哪些记录在提交时被更新、插入或删除到某个clear-on-commit
    GTT
    或某个持久表中,并在其中标记有事务ID(
    current_Transaction
    )。然后,提交时的
    触发器将按时间戳重新标记这些记录(包括已删除的记录)。也许您最好放弃2层模型,切换到3层模型。数据库->应用服务器->多个客户端。然后,它应该是保持状态,哪个客户拥有哪个数据公文包,以及如何将最后一刻的更改复制到这些客户。我想我看到了问题所在,但你的叙述对我来说有点不清楚。@pilcrow“Edit1”补充道:“你能给我们展示一个非常简单的表,其中包含一些行、你尝试过的触发器以及你想要发生的事情吗?”。用其他词语解释目标。添加了一些代码示例。IMHO由于此问题影响所有行的所有类型的表,因此此问题的示例无法解释任何内容。您可以尝试在提交时使用
    ON COMMIT
    trigger。RAWT方案是按表触发器记录哪些记录被更新、插入或删除到某个clear-on-commit
    GTT
    alter trigger SYNC_ORDERS active after insert or update position 999 AS
    declare variable N timestamp; 
    begin
      N = cast('NOW' as timestamp);
      if (new.last_changed <> :N) then
        update ORDERS set last_changed= :N where ID=new.ID;
    end
    
    Query1.SQL.Text := 'SELECT * FROM orders WHERE last_changed >= ' + DateTimeToStr( latest_record );  
    Query1.Open;  
     latest_record := Query1.FieldByName('last_changed').asDateTime;   
    
    ID  TableID  Changed
    ===========================
    1   5   2019.11.27 19:36:21
    2   5   2019.11.27 19:31:19
    
    create trigger ORDERS_BI active before insert or update position 0 AS
    BEGIN
      IF (NEW.ID IS NULL) THEN
        NEW.ID = GEN_ID(GEN_ORDERS,1);
      RDB$SET_CONTEXT('USER_TRANSACTION', 'orders_table', current_timestamp);  
    END
    
    create trigger TRG_SYNC_AFTER_COMMIT ACTIVE ON transaction commit POSITION 1 as 
      declare variable N TIMESTAMP;
      declare variable T VARCHAR(255);
    begin
      N = cast('NOW' as timestamp);
      T = RDB$GET_CONTEXT('USER_TRANSACTION', 'orders_table');
    
      if (:T is not null) then begin
        if (:N < :T) then T = :N; --system time changed eg.: daylight saving" -1 hour
        if (datediff(second from :T to :N) > 60 ) then --more than 1min. passed
          insert into "SYNC_PAST_TIMES" (ID, TABLE_NUMBER, TRG_START, SYNC_TIME, C_USER)
            values (GEN_ID(GEN_SYNC_PAST_TIMES, 1), 31, cast(:T as timestamp), :N, CURRENT_USER);
      end;  
    
      T = RDB$GET_CONTEXT('USER_TRANSACTION', 'details_table');
    -- other tables ...
    
      when any do EXIT;
    end