请教大佬,我这 SQL 写的有没有问题?

2019-10-15 15:06:20 +08:00
 cl903254852

article(文章表):

article_content(文章内容表):

article_tag(标签表):

article_type(分类表):


其中 article(文章表)、article_content(文章内容表) 是一对一关系

article(文章表)、article_tag(标签表) 是多对多关系,关系表 tag_article 如下:

article(文章表)、article_type(分类表) 也是多对多关系,关系表 type_article 如下:


需求

查询所有文章,包含以下数据:

然后我自己写的 SQL 是这样的:

SELECT 
a.id, 
a.title,
GROUP_CONCAT( distinct t.tag_id),
GROUP_CONCAT( distinct type.type_id),
GROUP_CONCAT( distinct a_tag.tag_name),
GROUP_CONCAT( distinct a_type.type_name)
FROM article a  
JOIN tag_article t ON a.id=t.article_id
JOIN type_article type ON a.id = type.article_id 
JOIN article_tag a_tag ON a_tag.id=t.tag_id
JOIN article_type a_type ON a_type.id=type.type_id
GROUP BY a.id;

结果:

结果也能出来,但我心里总有点不踏实。

各位大佬,我这 SQL 写的有没有问题?或者不严谨的地方?

ps:鄙人也是刚入门 Mysql,轻喷☹️

3633 次点击
所在节点    程序员
32 条回复
wangyzj
2019-10-15 15:12:35 +08:00
表结构不大好
leewea
2019-10-15 15:15:22 +08:00
头像不错
xwbz2018
2019-10-15 15:43:43 +08:00
标签和分类可以冗余到文章表里
newtype0092
2019-10-15 15:47:53 +08:00
tag name 和 type name 这种最好放在 redis 里,查出来 id 之后去 redis 里拿出来,现在这样 join 出来很多多余数据。
你这种不用 left join 没有问题么?
cl903254852
2019-10-15 17:04:26 +08:00
@xwbz2018 我特意问过同事,他们也喜欢这样冗余,用一个字段来存关系。但我总觉得这样不好,我还是觉得把关系抽离成中间表才是正规做法。
cl903254852
2019-10-15 17:06:42 +08:00
@newtype0092 对的!大佬!!! 这样确实会 join 出来很多多余数据(left join 也是),是我使用姿势错了?。 请问怎么解决呢
cl903254852
2019-10-15 17:07:02 +08:00
@leewea 😹
cl903254852
2019-10-15 17:07:40 +08:00
@wangyzj 虚心请教,应该改成什么样才算好
gIrl1990
2019-10-15 17:17:26 +08:00
article(文章表)、article_tag(标签表) 是多对多关系
article(文章表)、article_type(分类表) 也是多对多关系

有木有感觉其中一个是多余的? 都是多对多 那“标签”和“分类”有啥子区别?
xwbz2018
2019-10-15 17:28:30 +08:00
@cl903254852 #5 标签和类型会不会修改?标签和类型多不多?我 join 用的不好,你看看没有分类、标签的数据能不能查出来
linxiaojialin
2019-10-15 17:28:37 +08:00
为啥执着于一条 SQL 查出所有数据呢?可以分成 4 次查出来的。

另外,如果你是 PHP && Laravel 的话,设置好 Model Relation,可以用 with 解决 N+1 的问题,例如:
```
$articles = Article::query()->with(['content', 'tags', 'types'])->paginate(10);
```
cl903254852
2019-10-15 17:31:40 +08:00
@linxiaojialin 我用的 Nodejs。 多次查会影响性能 我尽量一次查出来
cl903254852
2019-10-15 17:32:36 +08:00
@gIrl1990 分类范围比标签大。 请不要关心业务问题
ebony0319
2019-10-15 17:44:10 +08:00
我用 Postgresql 给你重构一下:
```sql
SELECT
a.id,
a.title,
string_agg((select distinct a_tag.tag_name from article_tag a_tag inner join
ag_article t on a.id=t.article_id inner join
type_article type ON a.id = type.article_id inner join
article_type a_type ON a_type.id=type.type_id),',')
FROM article a
```
gIrl1990
2019-10-15 18:03:28 +08:00
@cl903254852 https://v2ex.com/t/609544?p=1#r_8031352
这个“范围” 区别体现在哪?按你的“标签”“分类”设计 A 文章分在标签 b 和 A 文章分在分类 b 有啥子区别?
gz911122
2019-10-15 18:12:35 +08:00
@cl903254852 冗余下去好一些..
单独出来没太大必要啊...

不过这种帖子文字类的用 mongo 比较舒服,postgre 也行 mysql 完全是给自己制造复杂度...
wongyusing
2019-10-15 18:30:26 +08:00
你这样的表结构感觉很奇怪啊
文章表、文章内容表可以合并在一起。
没必要设置成一对一。
而文章类型和文章标签为什么都用多对多啊??

正常来说,文章和文章类型属于外键关联。
文章和文章标签是多对多。

而且你的分类哪里不应该用 type,在某些编程语言中属于是关键字。
应该用 category
inhzus
2019-10-15 18:44:33 +08:00
合理的逻辑应该是 类型和文章一对多,文章和标签多对多,
taogen
2019-10-15 18:52:52 +08:00
主键关联没什么大问题,就是业务关联看起来有点多。关联太多性能会比放在一张表差,但这些减少了数据的冗余、不一致性。

建议用 left join。join 等于 inner join 取的是交集。
wangyzj
2019-10-15 18:55:28 +08:00
文章分类 article_type 单独一个表
文章标题 article 和文章内容 article_content 一张表,增加 article_type_id 字段外键对应 article_type 的 type_id, 再增加一个 tag text 字段,把所有标签排重放里面做成数组,用 Sequelize 定义 model 的时候加一个 get 方法自定义 JSON.loads 这个字段自动转换成数组取出

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/609544

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX