Sql 如何在SAP HANA中建立只读一次实施?

Sql 如何在SAP HANA中建立只读一次实施?,sql,hana,hana-sql-script,Sql,Hana,Hana Sql Script,背景:我是一个长期的MSSQL开发人员。。。我想知道的是如何从SAP HANA实现只读一次选择 高级伪代码: 通过db proc收集请求(查询) 带请求调用API 存储请求(响应)的结果 我有一个表(a),它是流程的输入源。一旦流程完成,它将把结果写入另一个表(B) 如果我只是在表a中添加一列,以避免并发处理器从表a中选择相同的记录,也许这一切都解决了 我想知道如何在不向源表A添加列的情况下执行此操作 我尝试的是表a和表B之间的左外部联接,以从a中获取B中没有对应行(尚未)的行。这不起作用,或者

背景:我是一个长期的MSSQL开发人员。。。我想知道的是如何从SAP HANA实现只读一次选择

高级伪代码:

  • 通过db proc收集请求(查询)
  • 带请求调用API
  • 存储请求(响应)的结果
  • 我有一个表(a),它是流程的输入源。一旦流程完成,它将把结果写入另一个表(B)

    如果我只是在表a中添加一列,以避免并发处理器从表a中选择相同的记录,也许这一切都解决了

    我想知道如何在不向源表A添加列的情况下执行此操作

    我尝试的是表a和表B之间的左外部联接,以从a中获取B中没有对应行(尚未)的行。这不起作用,或者我没有实现任何处理器只处理一次行

    我有一个存储过程来处理批选择:

    /*
     *      getBatch.sql
     *
     *      SYNOPSIS:  Retrieve the next set of criteria to be used in a search
     *                 request.  Use left outer join between input source table
     *                 and results table to determine the next set of inputs, and
     *                 provide support so that concurrent processes may call this
     *                 proc and get their inputs exclusively.
     */
    alter procedure "ACOX"."getBatch" (
         in in_limit int
        ,in in_run_group_id varchar(36)
        ,out ot_result table (
             id bigint
            ,runGroupId varchar(36)
            ,sourceTableRefId integer
            ,name nvarchar(22)
            ,location nvarchar(13)
            ,regionCode nvarchar(3)
            ,countryCode nvarchar(3)
        )
    ) language sqlscript sql security definer as
    begin       
    
        -- insert new records:
        insert into "ACOX"."search_result_v4" (
             "RUN_GROUP_ID"
            ,"BEGIN_DATE_TS"
            ,"SOURCE_TABLE"
            ,"SOURCE_TABLE_REFID"   
        )
        select
             in_run_group_id as "RUN_GROUP_ID"
            ,CURRENT_TIMESTAMP as "BEGIN_DATE_TS"
            ,'acox.searchCriteria' as "SOURCE_TABLE"
            ,fp.descriptor_id as "SOURCE_TABLE_REFID"
        from 
            acox.searchCriteria fp
        left join "ACOX"."us_state_codes" st
            on trim(fp.region) = trim(st.usps)
        left outer join "ACOX"."search_result_v4" r
            on fp.descriptor_id = r.source_table_refid
        where
            st.usps is not null
            and r.BEGIN_DATE_TS is null
        limit :in_limit;
        
        -- select records inserted for return:
        ot_result =
        select
             r.ID id
            ,r.RUN_GROUP_ID runGroupId
            ,fp.descriptor_id sourceTableRefId
            ,fp.merch_name name
            ,fp.Location location
            ,st.usps regionCode
            ,'USA' countryCode
        from 
            acox.searchCriteria fp
        left join "ACOX"."us_state_codes" st
            on trim(fp.region) = trim(st.usps)
        inner join "ACOX"."search_result_v4" r
            on fp.descriptor_id = r.source_table_refid
            and r.COMPLETE_DATE_TS is null
            and r.RUN_GROUP_ID = in_run_group_id
        where
            st.usps is not null
        limit :in_limit;
    
    end;
    
    当运行7个并发处理器时,我得到了35%的重叠。也就是说,在5000个输入行中,得到的行数是6755。运行时间约为7分钟

    目前,我的解决方案包括向源表添加列。我想避免这种情况,但它似乎使实现更简单。我将很快更新代码,但它在插入之前包含一条update语句

    有用的参考资料:

    首先:在任何RDBMS(包括MS SQL)中都没有“只读-一次”。 从字面上看,这意味着给定的记录只能读取一次,然后在所有后续读取中“消失”。(这实际上就是队列所做的,或者是众所周知的队列特例:管道)

    我想那不是你想要的

    相反,我相信您希望实现一种类似于“一次且仅一次”的处理语义,即“恰好一次”消息传递。虽然这是在潜在的分区网络中实现的,但在数据库的事务上下文中也是可能的

    这是一个常见要求,例如,批量数据加载作业应仅加载到目前为止尚未加载的数据(即,在上次批量加载作业开始后创建的新数据)

    抱歉,前面的文字太长了,但任何解决方案都将取决于我们想要实现的目标。我现在会找到一个解决办法

    主要的RDBMS早就发现,如果目标是实现高事务吞吐量,那么阻塞读卡器通常是一个糟糕的想法。因此,HANA永远不会阻止读卡器(ok,永远不会,但在正常操作设置中)。 “精确一次”处理要求的主要问题实际上不是读取记录,而是处理多次或根本不处理的可能性

    这两个潜在问题都可以通过以下方法解决:

  • 选择。。。对于更新…
    应处理的记录(基于未处理的记录、最多N条记录、奇偶ID、邮政编码等)。这样,当前会话具有更新事务上下文,并对所选记录进行独占锁定。其他事务仍可以读取这些记录,但没有其他事务可以锁定这些记录-既不适用于
    更新
    删除
    ,也不适用于
    选择。。。更新…

  • 现在,您可以进行处理了——不管这涉及到什么:合并、插入、更新其他表、写入日志条目

  • 作为处理的最后一步,您希望将记录“标记”为已处理。具体如何实施并不重要。 可以在表中创建一个
    processed
    -列,并在处理记录时将其设置为
    TRUE
    。或者可以有一个单独的表,其中包含已处理记录的主键(可能还有一个加载作业id,用于跟踪多个加载作业)。 无论以何种方式实现,这是一个时间点,需要捕获该
    已处理的
    状态

  • 提交
    回滚
    (以防出错)。这将
    提交
    写入目标表的记录、已处理的状态信息,它将从源表释放独占锁

  • 如您所见,步骤1通过选择所有可处理的想要的记录(即,它们不被任何其他进程独占锁定),解决了可能丢失记录的问题。 步骤3通过跟踪已处理的记录,处理可能被多次处理的记录的问题。显然,必须在步骤1中检查此跟踪-这两个步骤是相互关联的,这就是我明确指出它们的原因。最后,所有处理都发生在同一个DB事务上下文中,允许在整个事务中保证
    COMMIT
    ROLLBACK
    。这意味着,在提交记录处理时,不会丢失任何“记录标记”

    现在,为什么这种方法比使记录“不可读”更可取? 因为系统中的其他进程

    可能源记录仍由事务系统读取,但从未更新。此事务系统不必等待数据加载完成

    或者,有人想对源数据进行一些分析,还需要读取这些记录

    或者,您可能希望并行加载数据:可以轻松跳过锁定的记录,只处理当前“可用于更新”的记录。关于这一点,请参见示例

    好吧,我猜你希望有更容易消费的东西;唉,据我所知,这就是我处理此类需求的方法。