假设我想创建一个简单的数据库,让用户可以创建播放列表并添加多首歌曲。我只是希望能够找到在特定播放列表中添加的歌曲。
歌曲表:
`song_id` INT AUTO_INCREMENT PRIMARY KEY, `song_title` VARCHAR
播放列表表格:
`playlist_id` INT AUTO_INCREMENT PRIMARY KEY, `playlist_title` VARCHAR
什么是最好的选择呢?
playlist
表,并将逗号分隔的歌曲ID插入该列。我认为这不是一个合适的关系方式,但是做到了。或
playlist_id INT, song_id INT
类似,其中两列都是外键。 现在,如果第二个选项更好,我应该添加另一个列作为主键吗?auto_increment知道它在任何地方都没用吗?因为我在线阅读了一些文章,其中许多文章表明没有表格的主键会以负面的方式显着影响其表现。
答案 0 :(得分:4)
你应该强烈倾向于选项二,即创建一个将播放列表ID与歌曲ID相关联的表格。在这种情况下,您实际上可以创建一个主键,它是播放列表和歌曲ID的组合。
CREATE TABLE playlist_songs (
song_id INT,
playlist_id INT,
PRIMARY KEY (song_id, playlist_id)
)
至于您还是否需要playlist_songs
上的自动增量列,这取决于您的具体情况。从业务逻辑的角度来看,您可能不需要它,因为您可能正在使用已存在的两列来操作表。
答案 1 :(得分:2)
你的问题有两个方面 - 抽象的,哲学的观点和实际意义。
哲学上,我们决定数据库设计是否“好”的方式是看它是否正常化。 您的设计中有两个实体 - 歌曲和播放列表。你有两种关系 - 一首歌可以属于0..n播放列表,一个播放列表包含0..n首歌曲。 您希望单独存储这些事实,而不是将它们捆绑在一起。这意味着桥接表是“最佳”的,因为它存储单个事实(歌曲x属于播放列表y),与歌曲或播放列表的存在无关。 替代设计将几个事实存储在一行中 - “存在播放列表,并且具有以下歌曲”。
第二个哲学问题是“我如何唯一地识别事实?”。在你的桥接表中,独特的事实是“歌曲x属于播放列表y”。它只能属于该播放列表一次(实际上,这可能不是真的 - 您可能需要一列来指示歌曲出现的顺序)。 这意味着您的业务领域中有一个自然的复合键。从哲学上讲,这是您想要用来识别这些记录的内容,因此这应该是您的主要密钥。
从实际角度来看,第一个问题(选项一或选项二)取决于您的应用程序如何工作和发展。 如果你必须回答“这首歌出现在哪个播放列表中”这个问题,那么选项2要好得多 - 选项一需要一个where子句,如'where playlist.songs like'%songid,&',这将非常慢。 如果您必须删除一首歌曲,并确保删除所有引用 - 选项2要好得多。选项一会很慢找到,更新逗号分隔列表的代码会很糟糕。 如果您必须在播放列表中间插入歌曲,则选项2要好得多。
关于“我如何分配我的主键”的问题 - 我想你可能误解了这些文章。主键是逻辑概念,不需要是自动递增的整数。只要你有好的索引(并且索引与主键不同),你的表现就会很好。
答案 2 :(得分:1)
第二个选项是FAR更可取。
对于额外的主键,虽然没有必要,但我倾向于使用一个,即使只是为了更容易处理该表中的行。
例如,假设您要删除十几行,可以使用 IN(逗号分隔的ID列表),而不是检查行中每对字段的where子句。
顺便说一句,第二种选择更可取的原因有很多: -
答案 3 :(得分:1)
我会说选项二对你最有利。然后,您将拥有如下表格:
playlist_items表
pi_id
INT AUTO_INCREMENT PRIMARY KEY
pi_song_id
INT
pi_playlist_id
INT
有了这个,您可以在将来添加功能,如果需要,例如:
pi_dateadded
DATETIME
答案 4 :(得分:1)
在InnoDB中请记住,您可以通过按逻辑顺序遍历主键索引来访问行,因此您需要询问如何查找行。遍历索引是O(log(N))复杂度,但如果您使用的是二级索引,那么您将执行两次。
通常在InnoDB中使用单列pkey更好,但可能有例外。
答案 5 :(得分:-1)
playlist_table
`playlist_id` INT AUTO_INCREMENT PRIMARY KEY, `playlist_title` VARCHAR
songs_table
`song_id` INT AUTO_INCREMENT PRIMARY KEY, `song_title` VARCHAR,playlist_id INT FOREIGN KEY (playlist_id) REFERENCES playlist_table(playlist_id)
如果您想要搜索,请使用联接来查找歌曲
select * from songs_table left join playlist_table on(songs_table.playlist_id=playlist_table.playlist_id)