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