article
(文章表):article_content
(文章内容表):article_tag
(标签表):article_type
(分类表):查询所有文章,包含以下数据:
然后我自己写的 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;
结果:
结果也能出来,但我心里总有点不踏实。
ps:鄙人也是刚入门 Mysql,轻喷☹️
1
wangyzj 2019-10-15 15:12:35 +08:00
表结构不大好
|
2
leewea 2019-10-15 15:15:22 +08:00
头像不错
|
3
xwbz2018 2019-10-15 15:43:43 +08:00
标签和分类可以冗余到文章表里
|
4
newtype0092 2019-10-15 15:47:53 +08:00
tag name 和 type name 这种最好放在 redis 里,查出来 id 之后去 redis 里拿出来,现在这样 join 出来很多多余数据。
你这种不用 left join 没有问题么? |
5
cl903254852 OP @xwbz2018 我特意问过同事,他们也喜欢这样冗余,用一个字段来存关系。但我总觉得这样不好,我还是觉得把关系抽离成中间表才是正规做法。
|
6
cl903254852 OP @newtype0092 对的!大佬!!! 这样确实会 join 出来很多多余数据(left join 也是),是我使用姿势错了?。 请问怎么解决呢
|
7
cl903254852 OP @leewea 😹
|
8
cl903254852 OP @wangyzj 虚心请教,应该改成什么样才算好
|
9
gIrl1990 2019-10-15 17:17:26 +08:00
article(文章表)、article_tag(标签表) 是多对多关系
article(文章表)、article_type(分类表) 也是多对多关系 有木有感觉其中一个是多余的? 都是多对多 那“标签”和“分类”有啥子区别? |
10
xwbz2018 2019-10-15 17:28:30 +08:00
@cl903254852 #5 标签和类型会不会修改?标签和类型多不多?我 join 用的不好,你看看没有分类、标签的数据能不能查出来
|
11
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); ``` |
12
cl903254852 OP @linxiaojialin 我用的 Nodejs。 多次查会影响性能 我尽量一次查出来
|
13
cl903254852 OP @gIrl1990 分类范围比标签大。 请不要关心业务问题
|
14
ebony0319 2019-10-15 17:44:10 +08:00
|
15
gIrl1990 2019-10-15 18:03:28 +08:00
@cl903254852 https://v2ex.com/t/609544?p=1#r_8031352
这个“范围” 区别体现在哪?按你的“标签”“分类”设计 A 文章分在标签 b 和 A 文章分在分类 b 有啥子区别? |
16
gz911122 2019-10-15 18:12:35 +08:00
|
17
wongyusing 2019-10-15 18:30:26 +08:00
你这样的表结构感觉很奇怪啊
文章表、文章内容表可以合并在一起。 没必要设置成一对一。 而文章类型和文章标签为什么都用多对多啊?? 正常来说,文章和文章类型属于外键关联。 文章和文章标签是多对多。 而且你的分类哪里不应该用 type,在某些编程语言中属于是关键字。 应该用 category |
18
inhzus 2019-10-15 18:44:33 +08:00 via Android
合理的逻辑应该是 类型和文章一对多,文章和标签多对多,
|
19
taogen 2019-10-15 18:52:52 +08:00 via Android
主键关联没什么大问题,就是业务关联看起来有点多。关联太多性能会比放在一张表差,但这些减少了数据的冗余、不一致性。
建议用 left join。join 等于 inner join 取的是交集。 |
20
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 这个字段自动转换成数组取出 |
21
zeraba 2019-10-15 18:56:06 +08:00 via Android
先恢复一对一,再 join,笛卡尔积很可怕,比如文章对应的标签,先按照文章 id group by 再 concat 最后关联就都没有重复了
|
22
wangyzj 2019-10-15 18:59:08 +08:00
@cl903254852 酱紫俩表就解决问题了,基本上一次 update 操作,复杂的都没有了,text 可以做全文检索,虽然不咋滴
多对多的话把 acticle_type_id 字段做成 list 结构,标签我觉得就不用做表了 |
23
cl903254852 OP @gIrl1990 可以不讨论这个吗,你就当产品是白痴,他就这么设计的。我提问题只是想知道这个 SQL 有没有更好的写法😹😹😹
|
24
cl903254852 OP @wongyusing 原谅我的无知,我才开始学 mysql。把文章内容分出去,是考虑到如果数据量很大,而前端列表里不需要展示文章内容,只有在详情里才会查文章内容,这样性能应该会更好,type 这个是我没考虑周全 受教了~。
|
25
hosaos 2019-10-15 20:31:32 +08:00 1
分多次查询
1、先单表查询文章 2、根据文章 id 查询文章内容、标签、类型 连表查 等你数据多了就炸了 |
26
akira 2019-10-15 23:23:13 +08:00
典型的学院派,没啥大问题。
|
27
greed1is9good 2019-10-16 09:02:56 +08:00 via Android
@gIrl1990 估计他的标签应该是和关键字差不多意思吧,其实通常的做法是文章表有个关键字(标签)字段,show 文章的时候关键字(标签)做成查询链接,点击后查询出包含比关键字(标签)的内容。
|
28
cl903254852 OP @akira 哈哈 我是看视频学的
|
29
cl903254852 OP @greed1is9good 是的
|
30
cl903254852 OP @hosaos 大佬意思是连表查,如果连的表多,在数据量大的情况下容易爆炸。 但分多次查,也会导致性能下降吧,我的想法是如果能一次查出来最好,用子查询会降低性能。。。 不知道这样想对不对
|
31
wongyusing 2019-10-16 11:13:10 +08:00
@cl903254852 你用的是 select * from xxxx 吗?
你指定一下字段就行啦,这个不影响速度的啊。 |
32
hosaos 2019-10-16 15:18:32 +08:00
@cl903254852 数据量大的情况下 多次查询优于联表查
|