【问题标题】:Sequence vs identity序列与身份
【发布时间】:2012-04-21 04:24:41
【问题描述】:

SQL Server 2012 引入了Sequence 作为新功能,与 Oracle 和 Postgres 中的相同。序列在哪里比身份更受欢迎?为什么我们需要序列?

【问题讨论】:

  • 两者都使用后,我更喜欢 Identity 在数据库中全局使用。也就是说,您需要像 ObjectID 这样的自动递增数字并希望在许多表中使用它。制作序列然后使用应用程序(网站或应用程序等)根据序列号管理插入和更新表变得复杂。

标签: sql sql-server tsql sql-server-2012


【解决方案1】:

我想你会找到答案here

使用列的标识属性,您可以轻松生成 自动递增的数字(通常用作主键)。和 序列,它将是一个不同的对象,您可以将其附加到 插入时的表列。与身份不同,下一个数字为 列值将从内存而不是磁盘中检索 - 这使得 Sequence 比 Identity 快得多。我们会看到 这在接下来的例子中。

还有here

序列:SQL Server 社区已请求序列 多年来,它包含在此版本中。序列是用户 生成数字序列的定义对象。这是一个 使用序列的示例。

还有here

SQL Server 序列对象生成数字序列,就像 sql 表中的标识列。但是顺序的优势 numbers 是序列号对象,不限于单个 sql 表。

您还可以在 msdn 上阅读更多关于使用情况以及我们需要它的原因 (here):

序列是用户定义的模式绑定对象,它生成一个 根据规范的数值序列 序列已创建。生成数值序列 在定义的时间间隔内以升序或降序排列,并且可以 按要求循环(重复)。与标识列不同,序列是 与表无关。应用程序引用序列对象 接收它的下一个值。序列和序列之间的关系 表由应用程序控制。用户应用程序可以 引用一个序列对象并协调值键 多行和多表。

使用 CREATE 独立于表创建序列 序列语句。选项使您能够控制增量, 最大值和最小值、起点、自动重启 能力和缓存以提高性能。有关信息 选项,请参阅创建序列。

与标识列值不同,标识列值是在行被生成时生成的 插入,应用程序可以获取之前的下一个序列号 通过调用 NEXT VALUE FOR 函数插入行。序列 当调用 NEXT VALUE FOR 时分配编号,即使编号 永远不会插入到表中。 NEXT VALUE FOR 函数可以是 用作表定义中列的默认值。采用 sp_sequence_get_range 获取多个序列号的范围 一次。

序列可以定义为任何整数数据类型。如果数据类型 未指定,序列默认为 bigint。

【讨论】:

    【解决方案2】:

    序列和标识都用于生成自动编号,但主要区别在于标识是依赖于表的,而序列是独立于表的。

    如果您有一个需要全局维护自动编号的场景(在多个表中),您还需要在特定编号后重新启动间隔并且还需要缓存它以提高性能,这里是我们需要的地方序列而不是身份。

    【讨论】:

      【解决方案3】:

      虽然序列比标识列提供更多的灵活性,但我没有发现它们有任何性能优势。

      我发现使用标识的性能始终比使用序列进行批量插入快 3 倍。

      我插入了大约 150 万行,性能是:

      • 14 秒确认身份
      • 45 秒的序列

      我通过表默认值将行插入到使用序列对象的表中:

      NEXT VALUE for <seq> for <col_name>

      还尝试在 select 语句中指定序列值:

      SELECT NEXT VALUE for <seq>, <other columns> from <table>
      

      两者都比身份方法慢。我使用了序列的默认缓存选项。

      Arion 的第一个链接中引用的文章显示了逐行插入的性能,身份和序列之间的差异为 16.6 秒到 14.3 秒,对于 10,000 次插入。

      缓存选项对性能有很大影响,但对于更大的容量(+1M 行)而言,标识会更快

      请参阅此link,根据 utly4life 的评论进行深入分析。

      【讨论】:

      • 序列的缓存大小是多少。
      • 50,增加它确实会有所作为,但我记得身份仍然更快。
      • byobi.com/blog/2012/09/… 提供了各种配置的详细比较。表明缓存大小从 50 增加到 500 会产生大约 2 倍的速度差异。
      • 您是否建议序列比标识列慢?我有一个相反的印象,因为序列是在内存中的,不像从磁盘获取的身份。你的发现非常令人惊讶。很高兴你分享了。
      • 使用序列可以优化批量插入性能,方法是使用alter sequence increment by ... 为新行腾出空间,然后使用 base + row_number() 或其他任何实际值。
      【解决方案4】:

      我知道这有点老了,但想补充一点让我印象深刻的观察。

      我从身份切换到序列以使我的索引井井有条。后来我发现该序列不会随着复制而转移。由于序列不同步,我在两个数据库之间设置复制后开始出现密钥冲突。只是在你做出决定之前需要注意的事情。

      【讨论】:

        【解决方案5】:

        最近有点需要考虑身份与序列的问题。如果您可能想保持身份没有间隙,似乎 MSFT 现在建议序列。我们遇到了身份存在巨大差距的问题,但基于此突出显示的声明将解释我们的问题,即 SQL 缓存了身份,并且在重新启动后我们丢失了这些数字。

        https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property?view=sql-server-2017

        服务器重新启动或其他故障后的连续值 - SQL Server 可能出于性能原因缓存标识值,并且某些分配的值可能会在数据库故障或服务器重新启动期间丢失。这可能会导致插入时标识值出现间隙。如果间隙不可接受,则应用程序应使用其自己的机制来生成键值。使用带有 NOCACHE 选项的序列生成器可以将间隙限制为从未提交的事务。

        【讨论】:

        • 有一个很好的答案来解释为什么你要跳过 IDENTITY 数字 linkSEQUENCE 与此处描述的问题相同 link 但你可以通过设置更小的 CACHE 来限制它大小,但在速度方面需要权衡。
        【解决方案6】:

        我发现序列的最佳用途不是替换标识列,而是创建“订单号”类型的字段。

        换句话说,订单号向最终用户公开,并且可能附带业务规则。您希望它是唯一的,但仅使用标识列也不是真正正确的。

        例如,不同的订单类型可能需要不同的顺序,因此您可能有一个互联网订单的顺序,而不是内部订单。

        换句话说,不要将序列视为身份的简单替代品,而应将其视为身份不符合业务需求的情况。

        【讨论】:

          猜你喜欢
          • 2011-06-30
          • 1970-01-01
          • 1970-01-01
          • 2015-04-29
          • 1970-01-01
          • 2020-04-13
          • 2020-09-30
          • 2019-07-08
          • 2012-03-15
          相关资源
          最近更新 更多