【问题标题】:What is the best way to generate an ID for a SQL Insert?为 SQL 插入生成 ID 的最佳方法是什么?
【发布时间】:2009-02-24 17:47:47
【问题描述】:

生成将在 INSERT 语句中立即使用的 ID 号的最佳、独立于 DBMS 的方法是什么,同时保持 ID 大致按顺序排列?

【问题讨论】:

    标签: sql rdbms-agnostic


    【解决方案1】:

    独立于 DBMS?那是个问题。最常见的两种方法是自动递增列和序列,大多数 DBMS 只做其中一种,但不会同时做这两种方法。因此,与数据库无关的方法是让另一个表的一列具有一个值,您可以锁定、选择、更新和解锁。

    通常我会说“与 DBMS 无关”,并使用 PostgreSQL 中的序列或 MySQL 中的自动增量列来实现。就我的目的而言,同时支持这两种方法总比试图找出一种适用于任何地方的方法要好。

    【讨论】:

    • 这真的非常非常痛苦。我没有更好的独立于 DBMS 的解决方案,但我已经在某些地方看到了这种设计,而且这种设计不能很好地扩展(或者至少我没有看到它运作良好)。
    • 我希望我的 SQL 脚本尽可能便携。我想我正在寻找一个根本不存在的标准化水平。
    【解决方案2】:

    如果您可以使用您选择的编程语言创建Globally Unique Identifier (GUID) - 将其视为您的 id。

    在进行故障排除时,它们更难使用(输入 INT 的where 条件要容易得多),但也有一些优点。通过在本地将 GUID 分配为您的键,您可以轻松地建立父子记录关系,而无需先将父级保存到数据库并检索 id。而且由于 GUID,根据定义,是唯一的,您不必担心增加服务器上的密钥。

    【讨论】:

      【解决方案3】:

      有自动递增或顺序

      这是什么意思,这是您最不担心的事情?

      您将如何处理 SQL 本身? MySQL 有限制,

      SQL Server 有顶,

      Oracle 有排名

      还有一百万个其他的东西,比如触发器、改变表语法等等

      【讨论】:

        【解决方案4】:

        是的,原始 SQL 中的明显方式(以及我的偏好顺序)是 a) 序列 b) 自增字段。更好、更现代、更独立于 DBMS 的方法是根本不接触 SQL,而是使用(好的)ORM。

        【讨论】:

          【解决方案5】:

          没有通用的方法来做到这一点。如果有,每个人都会使用它。从定义上讲,SQL 厌恶这个想法 - 它是基于集合的逻辑的一种反模式(尽管在许多实际案例中很有用)。

          您尝试从其他地方插入标识值的最大问题是当 SQL 语句涉及多条记录时,必须同时生成多个值。

          如果您需要它,请将其作为数据库选择要求的一部分,以便与您的应用程序一起使用。任何严肃的 DBMS 产品都会提供自己的使用机制,并且很容易围绕 DML 中的差异进行编码。变化几乎都在 DDL 中。

          【讨论】:

            【解决方案6】:

            我总是选择特定于数据库的解决方案,但如果你真的这样做,通常的方法是实现你自己的序列。您的 RDBMS 必须支持事务。

            您创建一个包含 int 列的序列表并使用第一个数字作为种子,然后您的事务逻辑看起来像这样

            开始交易 更新 tblSeq 设置 intID = intID + 1 从 tblSeq 中选择 @myID = intID 插入 tblData (intID, ...) 值 (@myID, ...) 结束交易

            事务强制写入锁,这样下一个排队的插入不能在记录插入到 tblData 之前更新 tblSeq 值。只要所有插入都通过此事务,那么您生成的 ID 就是按顺序生成的。

            【讨论】:

              【解决方案7】:

              使用自动递增的 id 列。

              【讨论】:

              • 我认为“独立于 DBMS”意味着自动增量列是不可能的。 AFAIK 生成此类列的语法对于所有常见数据库都不相同。
              • 许多流行的 DBMS 没有任何类型的自动增量列类型。
              【解决方案8】:

              真的有理由让它们按顺序排列吗?如果您只是将其用作 ID,那么您应该只能使用 UUID 的一部分或 md5(now()) 的前几个数字。

              【讨论】:

                【解决方案9】:

                你可以花点时间按摩一下。相当于

                DateTime.Now.Ticks
                

                所以应该是 YYYYMMDDHHMMSSSS

                【讨论】:

                • 当两个用户同时插入一条记录时,请务必包含某种类型的机器 ID,以应对罕见的事件。不太可能,但仍有可能。如果时钟分辨率不够快,批量插入可能会成为问题。许多记录可能具有相同的刻度。
                • @Doug L. - 正确,这实际上取决于您正在进行的交易类型以及发生冲突的可能性。这几乎可以归结为 GUID 与 INT 的讨论,这是一场激烈的辩论。
                【解决方案10】:

                它可能有点横向方法,但一个好的 ORM 类型库可能至少能够隐藏差异。例如,在 Ruby 中有 ActiveRecord(通常用于但不完全与 Ruby the Rails Web 框架相关联),它具有迁移功能。在与平台无关的代码中声明的表定义中,数据类型、顺序 id 生成和索引创建等实现细节被推到您的视野之下。

                我已经在 SQLite 上透明地开发了一个模式,然后在 MS SQL Server 上实现了它,后来移植到了 Oracle。无需更改生成我的架构定义的代码。

                正如我所说,它可能不是您想要的,但封装变化的最简单方法是使用已经为您完成封装的库。

                【讨论】:

                  【解决方案11】:

                  仅使用 SQL,以下可能是其中一种方法:

                  1. 创建一个表以包含您需要的起始 id
                  2. 首次部署应用程序时,应用程序应读取其上下文中的值。
                  3. 此后,根据需要增加 id(以线程安全的方式) 3.1 将 id 写入数据库(以线程安全的方式),该数据库始终保持更新值 3.2 不写入数据库,在内存中不断递增(线程安全方式)
                  4. 如果由于某种原因服务器出现故障,请将当前 id 值写入数据库
                  5. 当服务器再次启动时,它将从上次离开的位置进行选择。

                  【讨论】:

                    猜你喜欢
                    • 2017-06-14
                    • 2014-01-31
                    • 2010-11-02
                    • 1970-01-01
                    • 2019-05-28
                    • 2014-12-15
                    • 2012-03-04
                    • 1970-01-01
                    相关资源
                    最近更新 更多