为简单起见,我们假设有一个 Post 表和一个 Tags 表(不是实际用例,但这将使它保持简单)
帖子表
id | title
--------------------------------
1 | Random Text Here
2 | Another Post About Stuff
标签表
id | tag
--------------------------------
1 | javascript
2 | node
3 | unrelated-thing
posts_tags 表
id| post_id | tag_id
--------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 2
一个帖子可以有多个标签,一个标签可以与多个帖子相关联。
Web 应用程序假设 让我们假设添加/删除标签不会触发 Web 应用程序中针对链接表的单个异步操作。 相反,用户将编辑帖子(添加或删除任何已创建的标签)然后点击保存。 Web 应用程序会将包含与帖子关联的标签 ID 数组的 JSON 提交到服务器,然后服务器将处理代码中的更新请求。
例如,post_id=1
仅与 tag_id=[1,2]
一起提交,因此 tag=3
需要删除为链接表中的关联。
如果帖子或标签被删除,我会设置 ON DELETE CASCADE
- posts_tags.post_id
- posts_tags.tag_id
但是,在更新与帖子关联的标签的实例中,更新链接表数据的最佳方式是什么?
选项 1:
- 获取已编辑帖子的所有帖子标签
SELECT * FROM posts_tags WHERE post_id = 1
- 确定添加了哪些标签(并将 INSERT 插入到链接表中)
- 确定哪些标签已被删除(并从链接表中删除)
选项 2:
- 删除链接表中所有带有post_id的标签
- 将所有提交的标签插入链接表
选项 3:
- 我没有考虑的事情:)
随着表的增长,选项 2 是否会对索引产生更大的性能影响?
编辑:
- 为清楚起见,实际的帖子和标签数据未更改或删除。这纯粹是关于更新帖子的相关标签
- 我使用的数据库是 PostgreSQL 9.6
最佳答案
从性能的角度来看,选项 2 会很好 - 比选项 1 好得多,因为您有一个删除旧关联的操作,然后是一堆插入语句。在选项 1 中,您有更多查询(您的第一个查询是检索关联,然后是删除(如果适用))。
只要您的表在 post_id 上有索引,那么 delete * from posts_tags where post_id = ?
会快如闪电,即使是在一个巨大的表上也是如此。
还有一个选择...
posts_tags 表
id| post_id | tag_id | version_id
--------------------------------
1 | 1 | 1 | 0
2 | 1 | 2 | 0
3 | 1 | 3 | 1
4 | 2 | 2 | 0
5 | 1 | 1 | 2
6 | 1 | 3 | 2
在这种情况下,您使用版本控制机制来确定“当前”关联 (max(version_id)),因此您永远不必删除任何内容 - 您只需插入新行。
在实践中,这可能不会更快,但它确实为您省去了“删除”查询。
关于database - 如何更新多对多链接表中的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46603769/