使用datetime float表示作为主键

时间:2009-08-23 12:27:49

标签: floating-point primary-key

根据我的经验,我了解到使用代理INT数据类型列作为主键esp。与使用GUID或char / varchar数据类型列作为主键相比,IDENTITY键列提供更好的性能。 我尝试尽可能使用IDENTITY键作为主键。但最近我遇到了一个模式,其中表格是水平分区的,并通过分区视图进行管理。因此,表格不能具有IDENTITY列,因为这会使分区视图不可更新。解决此问题的一个方法是创建一个带有标识列的虚拟“keygenerator”表,以生成主键的ID。但这意味着每个分区视图都有一个'keygenerator'表。 我的下一个想法是使用float作为主键。原因是我设计的以下关键算法

DECLARE @KEY FLOAT

SET @KEY = CONVERT(FLOAT,GETDATE())/100000.0 

SET @KEY = @EMP_ID + @KEY

Heres how it works.

CONVERT(FLOAT,GETDATE()) 

给出当前日期时间的浮点表示,因为内部所有日期时间都由SQL表示为浮点值。

CONVERT(FLOAT,GETDATE())/100000.0 

将浮点表示转换为完整的十进制值,即所有数字都被推到“。”的右侧。

@KEY = @EMP_ID + @KEY

将Employee ID添加为此十进制值的整数。

逻辑是,员工ID保证在会话中是唯一的,因为员工不能同时连接多个应用程序。每次生成密钥时,对于同一名员工,当前日期时间将是唯一的。

所有员工会话中的所有唯一密钥以及跨时间。

因此对于Emp Ids 11和12,我有关键值,如12.40046693321566357,11.40046693542361111

但是,与选择GUID或char / varchar作为主键相比,我担心float数据类型是否为主键提供了好处。同样重要的是因为分区浮点列将成为复合键的一部分。

3 个答案:

答案 0 :(得分:1)

我不会考虑这种非正统的密钥生成模式 - 这有一个糟糕的黑客的味道。你为什么不用整数?有许多方法和算法来协调分布式密钥生成。从锁定整个表格并搜索下一个免费ID,通过预先分配每个客户端的id范围,从客户特定信息中获取(类似于您的员工+时间建议)。

答案 1 :(得分:1)

  

同样重要的是因为分区浮动列将成为复合键的一部分。

什么?为什么?为了使这个基于员工/时间的价值独一无二,您在主键中还需要什么?而在该问题的另一方面,您的密钥的其他组件是否已经是唯一的?如果是这样,为什么不直接使用它们?

你的计划在我的口中留下了不好的味道。我不太清楚为什么,因为,我想的越多,看起来就越坚固。

  • 起初我担心表现。但浮点数只有8个字节(假设您的DBMS使用IEEE 754双倍),这并不是那么大。这并不比将64位整数作为密钥或两个32位整数更糟糕。你的密钥生成过程是唯一可能放慢速度的过程,但即便如此也是如此。
  • 然后我担心独特性。此方案不保证您不会两次生成相同的密钥。但鉴于你的断言用户和日期时间的组合将是唯一的,那么这可能实际上有效:
    • IEEE 754双精度具有53位精度。
    • 日期时间将使用42位。假设:
      • 日期时间的分辨率为1/300秒(3.33 ... ms)。这对MS SQL Server来说至少是这样。
      • ceiling(log 2 (86400 * 300 * 100000))= 42
    • 这为您的员工ID留下了9位。如果员工ID大于511,那么您将丢失部分日期时间,但它将在毫秒级。您的员工ID可能会达到131071,然后您将失去超过一秒的准确度。
  • 然后我担心以后查找关键值的困难。鉴于0.2!= 0.1 + 0.1问题,浮点平等的问题总是会浮现在脑海中。但是你没有理由对这个键值进行任何计算,并且可能在任何给定时间都是IEEE 754双格式(无论是在表中,存储过程变量中,还是在可执行文件中的变量中),然后它永远不会改变,可以被视为唯一的64位值。

在考虑了所有这些之后,您的方案看起来确实相对安全。关于没有对索引进行聚类的Edoode's suggestion是一个很好的问题,考虑到这一点,以及上面关于员工ID大小的警告,你可以使用这个方案生成主键,就像任何一个一样。其他方法。

我仍然怀疑它是否是最佳方法,或者是否甚至是必要的。

  • 复合键的其他组件是否可以单独使用(即作为自然键)?

  • 您可以 ,如您所知,在另一个表中保留顺序密钥种子。并且您只需要一个表,而不是每个分区一个表。您只需在此表中有两列:一列用于分区号,另一列用于该分区的当前标识值。

  • 使用GUID或varchar主键并不是不可能的。许多人在许多不同的桌子上这样做。它不会杀死你的表现。它可能比这个方案更直接,或者至少更容易理解。

  • 如果您的组合密钥已包含员工ID,则只需在密钥中添加日期时间列并将其称为一天。如果没有,您可以添加两列。你没有理由将两者混合在一起。

HTH

答案 2 :(得分:0)

由于你没有提到rdbms我会认为SQL服务器。创建主键时,还会创建该键上的聚簇索引。表按此键的顺序排序。当使用Guids作为主键(具有聚簇索引)时,每个插入意味着对表的重新排序。这也适用于您的浮动表示。除了其他问题,如果您希望使用此方案,请不要在此主键上创建聚簇索引。