在数据库中,我看到许多表Primary-Key(PK)
为AUTO_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_INCREMENT
作为主键表示弱模式设计?
假设我有另一个表Parents
,我需要将ChidNo
保留为Foreign Key (FK)
。那会很复杂。
如果存在递归关联,那么保持PK为AUTO_INCREMENT将会非常糟糕。
保持关系中的自动增量字段表示规范化不合适?
在某些表中,为了引入额外的AUTO_INCREMENT
字段,我希望将所有列保留为PK。我错了吗?
因为我的想法反对使用AUTO_INCREMENT
,请建议我保留AUTO_INCREMENT
字段的可用性?
答案 0 :(得分:3)
自动增量PK列可以称为surrogate key。
在某些情况下,使用代理键可能是一种有用的优化:
因此,代理键有合法的好处。
也就是说,代理键经常被过度使用。许多应用程序框架(例如Ruby on Rails)使用默认值,即每个表都有一个名为ID
的整数代理键,无论它是否合适。您可以逐个表地指定PK列,但许多程序员将默认值作为规则,这导致他们有一些无意义的表设计。我见过的最糟糕的例子是,每个多对多表都有一个多余的ID
列。
对于它的价值,使用代理键与规范化无关。也就是说,规范化规则既不鼓励也不鼓励使用代理键。
每个支持代理键的数据库还提供一个函数,该函数返回当前会话中最近生成的id值。正如@JStead所提到的,在SQL Server中它是@@IDENTITY
或SCOPE_IDENTITY()
。在MySQL中,它是LAST_INSERT_ID()
。等等。
这些函数只返回一个值,因此如果在单个INSERT语句中插入多行,则无法获取所有生成的id值。这是一个限制。
答案 1 :(得分:2)
我同意它已被过度使用,但确实在RDBMS世界中占有一席之地。你没有指定数据库,这更像是一个哲学辩论然后任何实现,所以我将在下面的例子中使用sql server。
auto_increment或identity的最佳情况是,在宽或多列自然键的很多情况下,它比自然键更有效,更容易使用。
让我们看下表。
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)
)
此处的存储是身份版本2 *(4)+ 128字节,而自然密钥版本为4 * 128字节。
还可以通过table_id和column_nme上的唯一约束来保证唯一性。然后在父表中对table_nme,database_nme,server_nme进行唯一约束。老实说虽然我本来可能已经创建了一个数据库表,但table对database_id和table_nme只有一个唯一的约束,但是你明白了。如果为唯一索引选择了正确的列,则唯一性永远不应成为问题。
在大多数语言中获取以前插入的标识或auto_incremenet的值也是微不足道的。
select @@IDENTITY
or
select LAST_INSERT_ID()
每种语言都有办法获得最后一种语言。