sqlite 关联表中主键的设计

dy2hfwbg  于 2022-11-15  发布在  SQLite
关注(0)|答案(4)|浏览(167)

假设我有一个artist表,如下所示:
Id|名称

1|John Coltran
2|斯普林斯汀
song表,如下所示:
Id|标题

1|雨中歌唱
2|含羞草
现在一个艺术家可以写不止一首歌,一首歌也可以由不止一个艺术家写。我们有多对多的关系。我们需要一个关联表!
如何设计关联表的主键?
一种方法是定义两个外键的组合键,如下所示:

CREATE TABLE artist_song_map(
artist_id INTEGER,
song_id INTEGER,
PRIMARY KEY(artist_id, song_id),
FOREIGN KEY(artist_id) REFERENCES artist(id),
FOREIGN KEY(song_id) REFERENCES song(id)
)

另一种方法是使用合成主键,并对两个外键的元组施加唯一约束:

CREATE TABLE artist_song_map(
id INTEGER PRIMARY KEY AUTOINCREMENT,
artist_id INTEGER,
song_id INTEGER,
UNIQUE(artist_id, song_id),
FOREIGN KEY(artist_id) REFERENCES artist(id),
FOREIGN KEY(song_id) REFERENCES song(id)
)

哪种设计选择更好?

ia2d9nvy

ia2d9nvy1#

除非将表定义为WITHOUT ROWID,否则两个查询将创建相同的表。
第二种方法中的列id只为将以这两种方法之一创建的列rowid添加别名。
由于这是一个桥接表,您只需要将列artist_idsong_id的组合定义为UNIQUE
如果要使用其他表(如playlist表)扩展设计,则必须决定如何将其链接到现有表:

  • 如果artist_song_map中没有id列,则将playlist链接到songartist,就像您对artist_song_map所做的那样。
  • 如果artist_song_map中有id列,则可以将playlist直接链接到该id

我建议您不仅根据这3个表(songartistartist_song_map)做出决定,而且还根据您计划添加的表做出决定。

cyvaqqii

cyvaqqii2#

从逻辑上讲,这两种设计是相同的。但从管理层面看,身份设计更有效率。更少的磁盘碎片和未来的重新设计或维护将更容易。

bprjcwpo

bprjcwpo3#

桥接表通常不需要ID(AUTO_INCREMNT)来标识行。
链接栏(外键)是要点,因为它将艺术家链接到一首或多首歌曲)
只有当您需要该桥的特殊属性,或者您想引用该桥接表的一行并且不想有两个链接列时,您才会使用这样的ID字段,但正如我所说的,通常您永远不需要它

bvhaajcl

bvhaajcl4#

虽然通常差异不大,但复合/复合外键设计听起来更自然。单独的主键和关联的索引会占用数据库中的额外空间。此外,如果使用复合主键,则可以将表声明为没有ROWID。根据官方的docs,“在某些情况下,没有ROWID的表可以使用大约一半的磁盘空间量,并且可以操作快近两倍**”。

相关问题