Guid.NewGuid() 总是 return 所有行的 Guid 相同
Guid.NewGuid() always return same Guid for all rows
我从源转换的每一行都需要唯一的 GUID。
以下是示例脚本;代码 Guid.NewGuid() returns 所有行都相同
@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);
对该问题的快速总结是,您不应尝试通过依赖于生成新 Guid 的技术或任何其他具有 are "time-based" 的方法来分配唯一值。这样做的原因是,U-SQL 中的行可能会重新计算 - 由于顶点重试、性能优化等。
在这些情况下,值将重新分配一个新值并最终导致错误,而 运行 U-SQL 脚本 - 因为 U-SQL 需要行对于输入数据是确定性的。
而不是分配新的 Guid,使用 ROW_NUMBER Window 函数可以安全地向行添加新的唯一编号。我
@result =
SELECT
*,
ROW_NUMBER() OVER () AS UID
FROM @querylog;
请注意,U-SQL 是一种声明性语言,因此会将已知的非确定性函数(例如 Guid.NewGuid()
或 DateTime.Now
快照为每个脚本的一个值。
虽然您可以通过将此类函数包装到 C# 函数中来解决这个问题,但这种做法是非常不鼓励的,因为您使脚本具有不确定性,如果执行中的节点必须重试并且不会产生可重复的结果!
那么如何才能提供唯一编号呢?
选项是:
- 如果可以更改数据生成,请添加外部数据中已有的值。
- Skolemization:编写一个确定性表达式,将关键属性组合成一个唯一值。
- 对您阅读的数据使用
ROW_NUMBER() OVER ()
。如果您已经拥有需要保证唯一性的数据,请根据您的要求添加作业时间 运行 的时间标记,或者获取现有的最高值,或者获取足够大的间隔时间。
这是一个示例,它使用时间标记加上 ROW_NUBER()
来确保每次您 运行 脚本时每一行的 ID 都是唯一的,因为如上所述,U-SQL 将在每次脚本调用时评估 DateTime.Now
一次:
@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();
在代码隐藏中创建一个 udf:
namespace USQL_Namespace
{
public static class Udfs
{
public static string newGuidString()
{
return Guid.NewGuid().ToString();
}
}
并内联引用它:
@o =
SELECT USQL_Namespace.Udfs.newGuidString() AS newId;
我从源转换的每一行都需要唯一的 GUID。
以下是示例脚本;代码 Guid.NewGuid() returns 所有行都相同
@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);
对该问题的快速总结是,您不应尝试通过依赖于生成新 Guid 的技术或任何其他具有 are "time-based" 的方法来分配唯一值。这样做的原因是,U-SQL 中的行可能会重新计算 - 由于顶点重试、性能优化等。
在这些情况下,值将重新分配一个新值并最终导致错误,而 运行 U-SQL 脚本 - 因为 U-SQL 需要行对于输入数据是确定性的。
而不是分配新的 Guid,使用 ROW_NUMBER Window 函数可以安全地向行添加新的唯一编号。我
@result =
SELECT
*,
ROW_NUMBER() OVER () AS UID
FROM @querylog;
请注意,U-SQL 是一种声明性语言,因此会将已知的非确定性函数(例如 Guid.NewGuid()
或 DateTime.Now
快照为每个脚本的一个值。
虽然您可以通过将此类函数包装到 C# 函数中来解决这个问题,但这种做法是非常不鼓励的,因为您使脚本具有不确定性,如果执行中的节点必须重试并且不会产生可重复的结果!
那么如何才能提供唯一编号呢?
选项是:
- 如果可以更改数据生成,请添加外部数据中已有的值。
- Skolemization:编写一个确定性表达式,将关键属性组合成一个唯一值。
- 对您阅读的数据使用
ROW_NUMBER() OVER ()
。如果您已经拥有需要保证唯一性的数据,请根据您的要求添加作业时间 运行 的时间标记,或者获取现有的最高值,或者获取足够大的间隔时间。
这是一个示例,它使用时间标记加上 ROW_NUBER()
来确保每次您 运行 脚本时每一行的 ID 都是唯一的,因为如上所述,U-SQL 将在每次脚本调用时评估 DateTime.Now
一次:
@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();
在代码隐藏中创建一个 udf:
namespace USQL_Namespace
{
public static class Udfs
{
public static string newGuidString()
{
return Guid.NewGuid().ToString();
}
}
并内联引用它:
@o =
SELECT USQL_Namespace.Udfs.newGuidString() AS newId;