Sql 保持自动增量字段是不合适的设计吗?

Sql 保持自动增量字段是不合适的设计吗?,sql,normalization,rdbms,database,Sql,Normalization,Rdbms,Database,在数据库中,我看到许多表中的主键(PK)是AUTO\u INCREMENT类型 假设我创建了一个表Children,如下所示: CREATE TABLE Children( childNo INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY, name VARCHAR(25), age INTEGER, address VARCHAR(100) ) ChildNo是AUTO_INCREMENT,但是一旦我插入了一行,我如何知

在数据库中,我看到许多表中的主键(PK)是
AUTO\u INCREMENT
类型

假设我创建了一个表
Children
,如下所示:

CREATE TABLE Children(
  childNo INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY,
  name    VARCHAR(25),
  age     INTEGER,
  address VARCHAR(100) 
)
  • ChildNo
    AUTO_INCREMENT
    ,但是一旦我插入了一行,我如何知道为一个孩子(名字)分配了哪个值?
    PK的错误选择

  • 如果我搜索孩子的名字,效率会很低(而且不能保证是唯一的)。因此,我认为将
    自动增量
    作为主键表示架构设计薄弱?

  • 假设我有另一个表
    Parents
    ,我需要将
    ChidNo
    保留为
    外键(FK)
    。那就很复杂了

  • 如果存在递归关联,那么保持PK自动递增将非常糟糕

在关系中保留自动递增字段表示规范化不合适?

在某些表中,为了引入一个额外的
自动增量
字段,我想将所有列保留为PK。我错了吗


因为我反对使用
自动增量
,请建议我也使用
自动增量
字段

我同意这是过度使用的,但它确实在RDBMS世界中占有一席之地。您没有指定数据库,这比任何实现更具哲学意义,因此我将在下面的示例中使用sql server

自动增量或标识的最佳情况是,在许多情况下,如果是宽或多列自然关键点,则它比自然关键点更高效、更易于使用

让我们看下表

CREATE TABLE TABLE_OBJECT (
 Table_ID int identity(1,1),
 Server_NME varchar(128),
 Database_NME varchar(128),
 Table_NME varchar(128)
)

CREATE TABLE COLUMN_OBJECT (
 Column_ID int identity(1,1),
 Table_ID int not null,
 Server_NME varchar(128),
 Database_NME varchar(128),
 Table_NME varchar(128),
 Column_NME varchar(128)
)
现在让我们假设在这个场景中,我们想要将两个表连接在一起,但我们没有标识

select * from TABLE_OBJECT to
inner join COLUMN_OBJECT co on co.Server_NME = to.Server_NME
                          and co.Database_NME = to.Database_NME
                          and co.Table_NME = to.Table_NME
除此之外,写它也是非常低效的,我不得不读取6*(128)字节来比较一行

现在将其与下面的简单性进行比较

select * from TABLE_OBJECT to
inner join COLUMN_OBJECT co on co.Table_id = to.Table_ID
在上面的示例中,我只需要读取2*(4)个字节来比较一行。当您有很多行时,这是一个巨大的差异

此外,还有普通存储端

CREATE TABLE COLUMN_OBJECT (
     Server_NME varchar(128),
     Database_NME varchar(128),
     Table_NME varchar(128),
     Column_NME varchar(128)
    )

CREATE TABLE COLUMN_OBJECT (
     Column_ID int identity(1,1),
     Table_ID int not null,
     Column_NME varchar(128)
    )
与自然密钥版本4*128字节相比,该版本上的存储为标识版本2*(4)+128字节

还可以通过表id和列nme上的唯一约束来保证唯一性。然后在父表中对表、数据库、服务器进行唯一约束。老实说,虽然我可能也会创建一个数据库表,并且表对数据库id和表nme只有一个唯一的约束,但您明白了。如果为唯一索引选择了适当的列,则唯一性永远不会成为问题

在大多数语言中,获取先前插入的标识或自动增量的值也很简单

select @@IDENTITY
or
select LAST_INSERT_ID()

每种语言都有一种获取最后一种语言的方法。

自动递增的主键列可以称为

在某些情况下,使用代理键可能是一种有用的优化:

  • 如果表中没有其他列可以可靠地处理为候选键。例如,可能无法保证(姓名、年龄、地址)的组合在所有情况下都能唯一标识行。似乎不太可能有两个同名同龄的人住在同一个地址。但这并不是无效的。在这种情况下,使用代理键可以使所有其他列都不唯一
  • PK保持不变可能是可取的。例如,一个人可以改变他们的名字,但他们仍然是同一个人。当然,SQL允许更改PK值,但是引用PK by值的所有其他数据也必须更改。如果您的RDBMS支持带有更新级联的外键,那么您可以将其自动化。但是,如果您没有更新级联(例如Oracle),或者您没有外键(例如较旧的MySQL或SQLite),或者您的数据存储在RDBMS之外,该怎么办?使用代理键意味着任何“自然”数据列都可以自由更改值,而无需更改行的标识。代理项键值是任意的,与自然数据无关,因此这些键值永远不需要更改
  • 即使有可以用作候选键的列,也可能需要使用大量的列子集作为复合主键。密钥的存储变得庞大,当然比单个整数要庞大得多。因此,在存储效率方面,使用代理密钥有一个优势
  • 操纵多列PK也会让开发人员进行更多的编码工作,这仅仅是因为他们需要在JOIN和WHERE子句中编写更长的条件。此外,如果需求发生变化,以至于(姓名、年龄、地址)不再是一个足够的PK,那么您需要在PK中添加第四列,现在您必须更改所有应用程序中的所有SQL代码
因此,代理密钥具有合法的好处

也就是说,代理密钥经常被过度使用。许多应用程序框架(例如RubyonRails)使用默认设置,即每个表都有一个名为
ID
的整数代理键,而不管它是否合适。您可以在一个表一个表的基础上指定一个PK列,但是许多程序员将默认值作为一个规则,这导致他们有一些毫无意义的表设计。我见过的最糟糕的例子是,每个多对多表都有一个多余的
ID

无论如何,使用代理键与规范化无关。也就是说,规范化规则既不鼓励也不阻止使用代理键

每个支持代理键的数据库还提供一个函数,该函数返回当前数据库中最近生成的id值