Sql 保持自动增量字段是不合适的设计吗?
在数据库中,我看到许多表中的主键(PK)是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,但是一旦我插入了一行,我如何知
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代码
ID
的整数代理键,而不管它是否合适。您可以在一个表一个表的基础上指定一个PK列,但是许多程序员将默认值作为一个规则,这导致他们有一些毫无意义的表设计。我见过的最糟糕的例子是,每个多对多表都有一个多余的ID
列
无论如何,使用代理键与规范化无关。也就是说,规范化规则既不鼓励也不阻止使用代理键
每个支持代理键的数据库还提供一个函数,该函数返回当前数据库中最近生成的id值