Guid.NewGuid()总是为所有行返回相同的Guid

Pra*_*ore 4 u-sql

对于我从源头转变的每一行,我都需要独特的guid.
下面是示例脚本; 代码Guid.NewGuid()总是为所有行返回相同的代码

@Person =
    EXTRACT SourceId          int,
            AreaCode          string,
            AreaDetail         string,
            City        string
    FROM "/Staging/Person"
    USING Extractors.Tsv(nullEscape:"#NULL#");

@rs1 =
    SELECT 
    Guid.NewGuid() AS PersonId,
    AreaCode,
    AreaDetail,
    City    
    FROM @Person;

OUTPUT @rs1   
    TO "/Datamart/DimUser.tsv"
      USING Outputters.Tsv(quoting:false, dateTimeFormat:null);
Run Code Online (Sandbox Code Playgroud)

Mic*_*Rys 7

请注意,U型SQL是一个说明性语言,因此将快照已知的非确定性的功能,如Guid.NewGuid()DateTime.Now每一个脚本值.

虽然你可以通过将这些函数包装到C#函数中来解决这个问题,但是这种做法是非常不鼓励的,因为你使脚本不确定,如果执行中的节点必须重试并且不重做,则可能导致脚本失败产生可重复的结果!

那你怎么能提供一个唯一的号码?

选项是:

  1. 如果可以更改数据生成,请添加外部数据中已有的值.
  2. Skolemization:写一个确定性表达式,将关键属性组合成一个唯一值.
  3. 用于ROW_NUMBER() OVER ()您阅读的数据.如果您已经拥有需要保证唯一性的数据,请添加作业运行时间的时间刻度,或者获取最高现有值,或者根据您的要求获得足够大的间隔.

下面是一个使用时间标记加上的示例,ROW_NUBER()以确保每次运行脚本时每个行的id都是唯一的,因为如上所述,DateTime.Now每个脚本调用U-SQL将评估一次:

@data =
SELECT *
FROM (VALUES
      ( "John", "Doe" ),
      ( "Paul", "Miller" ),
      ( "Tracy", "Smith" ),
      ( "Jane", "Doe")
     ) AS T(firstname, lastname);

@res = 
SELECT DateTime.Now.Ticks+ROW_NUMBER() OVER () AS id, 
       firstname, lastname
FROM @data;

OUTPUT @res
TO "/output/data.csv"
USING Outputters.Csv();
Run Code Online (Sandbox Code Playgroud)


sav*_*enr 5

问题的快速摘要是,您不应尝试通过依赖于生成新Guid或任何其他基于“时间”的方法的技术来分配唯一值。这样做的原因是,由于顶点重试,性能优化等原因,可能会重新计算U-SQL中的行。

在这些情况下,这些值将重新分配一个新值,并最终在运行U-SQL脚本时导致错误-因为U-SQL要求行对于输入数据是确定性的。

不用分配新的Guid,而是使用ROW_NUMBER窗口函数,该函数可以安全地向行添加新的唯一数字。一世

@result =
    SELECT 
        *,
        ROW_NUMBER() OVER () AS UID
    FROM @querylog;
Run Code Online (Sandbox Code Playgroud)