Mysql 数据库设计是否支持Stackoverflow等多个标记?

Mysql 数据库设计是否支持Stackoverflow等多个标记?,mysql,database,database-design,database-schema,junction-table,Mysql,Database,Database Design,Database Schema,Junction Table,我有以下表格 文章表格 a_idINT primary unique nameVARCHAR 说明VARCHAR c_idINT 类别表格 idINT 猫名VARCHAR 现在我只是简单地使用 从文章中选择一个\u id、名称、描述、类别名称。a\u id=Category.id,其中c\u id={$id} 这给了我所有属于某一类别的文章以及类别名称。 每篇文章只有一个类别 我以类似的方式使用子类别(我有另一个名为sub_cat的表)。但并非每篇文章都有子类别。它可能属于多个类别。 我现在想用

我有以下表格

文章表格
a_idINT primary unique
nameVARCHAR
说明VARCHAR
c_idINT

类别表格
idINT
猫名VARCHAR

现在我只是简单地使用

从文章中选择一个\u id、名称、描述、类别名称。a\u id=Category.id,其中c\u id={$id}

这给了我所有属于某一类别的文章以及类别名称。
每篇文章只有一个类别

我以类似的方式使用子类别(我有另一个名为sub_cat的表)。
但并非每篇文章都有子类别。它可能属于多个类别。

我现在想用多个类别标记一篇文章,就像stackoverflow上的问题被标记一样(例如:使用多个标记,如PHP、MYSQL、SQL等)。

然后我必须显示(过滤)所有带有特定标记的文章(例如:使用PHP、PHP+MYSQL标记),我还必须显示标记以及文章名称,描述
有人能帮我重新设计数据库吗?(我在后端使用php+MySQL)

创建一个新表:

CREATE TABLE ArticleCategories(
    A_ID INT,
    C_ID INT,
    Constraint PK_ArticleCategories Primary Key (Article_ID, Category_ID)
)
(这是SQL server语法,可能与MySQL略有不同)

这称为“连接表”或“映射表”,它是在SQL中表达多对多关系的方式。因此,每当您想向文章中添加一个类别时,只需在该表中插入一行,其中包含文章和类别的ID

例如,您可以如下方式初始化它:

INSERT Into ArticleCategories(A_ID,C_ID)
    SELECT A_ID,C_ID From Articles
SELECT a_id,name,Description,cat_name 
FROM Articles 
LEFT JOIN  ArticleCategories ON Articles.a_id=ArticleCategories.a_id 
INNER JOIN Category ON ArticleCategories.c_id=Category.id 
WHERE Articles.a_id={$a_id}
现在,您可以从文章表中删除
c_id

要获取单个文章的所有类别,请使用如下查询:

INSERT Into ArticleCategories(A_ID,C_ID)
    SELECT A_ID,C_ID From Articles
SELECT a_id,name,Description,cat_name 
FROM Articles 
LEFT JOIN  ArticleCategories ON Articles.a_id=ArticleCategories.a_id 
INNER JOIN Category ON ArticleCategories.c_id=Category.id 
WHERE Articles.a_id={$a_id}

或者,要返回具有类似于某个字符串的类别的所有文章,请执行以下操作:

SELECT a_id,name,Description
FROM Articles 
WHERE EXISTS(   Select * 
                From ArticleCategories 
                INNER JOIN Category ON ArticleCategories.c_id=Category.id 
                WHERE Articles.a_id=ArticleCategories.a_id 
                  AND Category.cat_name LIKE '%'+{$match}+'%'
             )

(您可能需要调整最后一行,因为我不确定字符串参数是如何通过MySQL+PHP传递的。)

好的,RBarryYoung您问我关于引用/分析的问题,您得到了一个

此参考/分析基于MySQL服务器上的文档/源代码分析

INSERT Into ArticleCategories(A_ID,C_ID)
    SELECT A_ID,C_ID From Articles
在一个包含许多行的大型Articles表上,此副本将使CPU上的一个内核达到100%负载,并将创建一个基于磁盘的临时表,这将降低MySQL的整体性能,因为该副本会使磁盘压力过大。 如果这是一个一次性的过程,这并没有那么糟糕,但是如果你每次都运行这个过程,请进行计算

SELECT a_id,name,Description
FROM Articles 
WHERE EXISTS(   Select * 
                From ArticleCategories 
                INNER JOIN Category ON ArticleCategories.c_id=Category.id 
                WHERE Articles.a_id=ArticleCategories.a_id 
                  AND Category.cat_name LIKE '%'+{$match}+'%'
             )
注意不要将sqlfriddle上的执行时间视为实际情况,因为它是一个繁忙的服务器,要做出一个好的声明,时间会有很多变化,但请查看执行计划中要说的内容

请参见演示

这两个查询总是在表项目和两个相关子查询上触发一个完整的表扫描,如果您有一个包含许多记录的大型项目表,这就不好了。 这意味着性能取决于文章行的数量,即使您只需要类别中的文章

Select * 
                From ArticleCategories 
                INNER JOIN Category ON ArticleCategories.c_id=Category.id 
                WHERE Articles.a_id=ArticleCategories.a_id 
                  AND Category.cat_name LIKE '%'+{$match}+'%'
此查询是内部子查询,但当您尝试运行它时,MySQL无法运行,因为它依赖于Articles表的值,因此这是相关子查询。将对外部查询处理的每一行计算一次的子查询类型。确实不好

有更多的方法可以重写RBarryYoung查询,我将展示一种。 即使使用LIKE运算符,内部联接方式也更有效 注意,我有一个习惯,我从记录数最少的表开始,然后逐步向上,如果从表文章开始,如果MySQL优化器选择正确的计划,执行将是相同的。

SELECT 
   Articles.a_id
 , Articles.name
 , Articles.description
FROM 
 Category

INNER JOIN
 ArticleCategories
ON
 Category.id = ArticleCategories.c_id

INNER JOIN
 Articles
ON 
 ArticleCategories.a_id = Articles.a_id

WHERE 
 cat_name LIKE '%php%';
;
请参见演示注意,这看起来更糟,因为它看起来需要检查更多行

注意,如果项目表的非记录数较低,RBarryYoung EXIST方式和内部联接方式将根据执行时间和更多证据执行大致相同的操作。当记录计数变大时,内部联接方式的伸缩性更好

EXISTS oeps现在需要检查更多的文章记录(即使它们没有与ArticleCategories表链接),因此现在查询效率较低 内部连接与第一个演示相同的解释计划

关于扩展的额外注意事项如果您还想按“不存在”的方式订购或分组,则情况会变得更糟,因为它更有可能创建一个基于磁盘的临时表,从而破坏MySQL的性能

还让我们分析EXIST方式和内部连接方式的类似“%php%”的vs='php'

存在方式

/(更多文章)解释告诉我这两种模式大致相同,但“php”应该快一点,因为类型列中的off const type vs ref,但像%php%一样,由于需要运行字符串比较算法,将使用更多的CPU

内部连接方式

/(更多文章)解释告诉我,类似“%php%”的速度应该较慢,因为还需要分析3行,但在这种情况下,速度不会太慢(您可以看到索引并没有真正以最佳方式使用)

RBarryYoung方式可以工作,但至少不能在MySQL服务器上保持性能 看到或
例如,将在包含大量记录的大型表上进行缩放,这是主题初学者需要的

我是否应该将与特定文章关联的所有类别存储到ArticleCategories中?i、 例如:A_ID 1和C_ID的3,4,6我在ArticleCategories中有3行?@Shrikanth是的,没错。@JoelBrown是的,这是通常的做法。@Shrikanth这执行得很好,这是在关系/SQL数据库中执行此操作的唯一正确方法。我向你保证你想做的任何其他事情