存储多对多模型(标签)数据的最佳实践

Best practice for storing data of many to many models (tags)

我想在关系数据库中表示公司模型。
一家公司与以下标签模型相关联:

一家公司可以为每个标签设置多个值(即一种商业模式、两个行业和三个核心技术)。
一个tag-value在一个特定的tag model中只能出现一次,但是可以出现在同名的不同tag model中(即价值SaaS的核心技术和价值SaaS的商业模式)

我想出了两个合法的选项来存储这个关系:

  1. 每个标签模型有一个 table 和一个相应的连接 table:

  2. 有一个带有标签 type 枚举字段的 tags table,它可以是可能的值之一 [sectorcore_technology, business_model]:

最终目标是能够获得所有具有特定标签组合的公司的结果集。

最初,我认为没有真正的区别,第二种方法可能稍微好一点,因为我们的 table 数量更少,而且越少越好,不是吗?!

但是,当我做了一个快速演示,生成了一些假数据,并尝试 运行 一些查询时,我发现查询的外观有很大差异,这可能也会影响案例中的性能我的数据库中有很多公司。

这是第一种方法的查询示例:

SELECT   c.id,
         c.NAME,
FROM     companies c
JOIN     companies_business_models cbm
ON       (
                  c.id = cbm.company_id)
JOIN     business_models bm
ON       (
                  cbm.business_model_id = bm.id)
JOIN     companies_sectors cs
ON       (
                  c.id = cs.company_id)
JOIN     sectors s
ON       (
                  cs.sector_id = s.id)
JOIN     companies_core_technologies cct
ON       (
                  c.id = cct.company_id)
JOIN     core_technologies ct
ON       (
                  cct.core_technology_id = ct.id)
WHERE    s.NAME IN ('Consumer Staples',
                    'Utilities')
AND      ct.NAME IN ('SaaS',
                     'Computer Vision')
AND      bm.NAME IN ('SaaS')
GROUP BY c.id
HAVING   count(DISTINCT s.NAME) = 2
AND      count(DISTINCT ct.NAME) = 2
AND      count(DISTINCT bm.NAME) = 1

对于 WHERE 子句,这种方法似乎很直接,但包含许多 table 和 JOIN

这是第二种方法的查询示例:

SELECT c.id,
       c.NAME,
FROM   companies c
       JOIN companies_tags ct
         ON ( c.id = ct.company_id )
       JOIN tags t
         ON ( ct.tag_id = t.id )
WHERE  ( t.type = 'core_technology'
         AND t.NAME IN ( 'SaaS', 'Computer Vision' ) )
        OR ( t.type = 'business_model'
             AND t.NAME IN ( 'SaaS' ) )
        OR ( t.type = 'sector'
             AND t.NAME IN ( 'Consumer Staples', 'Utilities' ) )
GROUP  BY c.id
HAVING Count(DISTINCT t.type, t.NAME) = 5 

这种方法在 JOIN 上似乎更简洁,但在 WHERE 子句上不太直接。

非常感谢阅读您对这个问题的看法,以及将性能放在首位的最佳做法是什么

谢谢!

首先,我必须感谢您花时间设计数据模型。我经常看到开发人员急于创建新数据库,但大多数时候这种做法适得其反。

您建议的两个模式是有道理的。我个人会选择第二个,原因有两个:首先,正如您所提到的,使用此架构,相关查询需要较少的连接操作,这可能非常耗时。其次,它更具可扩展性。如果在将来的某个时候您将不得不添加另一种类型的标记,那么使用第二个模式将非常容易,而第一个模式将需要更改,SQL 查询和可能的其他部分也将需要更改应用程序的 DAL。

我更喜欢第一个模型。一共有三种不同的属性。一个行业、一个核心技术、一个商业模式,是三个不同的东西。第一个模型知道,第二个模型不知道。

目前这没有什么不同。它们只是您分配给公司的标签。但这可能会改变。有时您可能会决定存在子业务模型,例如针对业务模型“特许经营”的“分销特许经营权”和“业务格式特许经营权”,您甚至可以将合同编号存储在其中。或者对于你想知道它们是否受到政府补贴以及公司是否获得补贴的行业。或者对于核心技术,现在有一个可用的 ISO 代码供您存储。

在您的第一个模型中,您会将所有这些属性和子表或父表放在它们所属的位置。在您的第二个模型中,您将拥有可空属性,您认为这些属性对某些实体是强制性的,而不适用于其他实体。

我并不是说您的第二个模型无法实现所有这些。这是。但是数据模型将变得模糊并且需要解释。第一个模型对于开始使用它的人来说仍然是干净和容易理解的,因为一切都清楚地布置了。

我也不是说我更喜欢第一个模型。我不。我更喜欢它,但我也看到了第二个的简单性。如果您非常确定实体将只保留普通标签,那么简单节拍可扩展。