【问题标题】:Database Design - Items and Regions数据库设计 - 项目和区域
【发布时间】:2011-12-03 07:02:17
【问题描述】:

我有数据库结构的设计问题。 目标是为我们的客户在某些地理区域提供的报价建立数据库。 每个优惠都可以在许多地区提供。

这些地区是分层的 - 示例:

subregion_1
  subregion_11
    region_111
    region_112
  subregion_12
    region_121
    region_122
subregion_2
  subregion_21
    region_221

现在我想将 offer_1 和该优惠的区域存储在数据库中。我会给你 3 个我必须实现的例子:

  • 当我的 offer_1 存储在 region_111 中时,我想在用户浏览 subregion_1、subregion_11 和 region_111 时显示此优惠
  • 如果 offer_1 存储在区域 subregion_11 和 region_121 中,则当用户浏览 subregion_1、subregion_11 以及 subregion_11、subregion_12 和 region_121 的所有分支时,应显示该优惠
  • 当我的 offer_1 存储在 subregion_1 中时,offer 会显示在 subregion_1 页面和 subregion_1 下的所有分支上。

我还必须提供一种方法来动态且非常快速地计算每个区域中不同报价的数量。 有人对如何处理这种设计有一些建议吗?

这是我目前所拥有的。

Regions
------------------------------------------------------------
| id     | level1 | level2 | level3 | name         | level |
------------------------------------------------------------
| 02     | 02     | null   | null   | subregion_1  | 1     |
| 0201   | 02     | 01     | null   | subregion_11 | 2     |
| 020103 | 02     | 01     | 03     | region_111   | 3     |
------------------------------------------------------------

Offers to regions
------------------------
| offer_id | region_id |
------------------------
| 1        | 020103    |
| 1        | 0202      |
------------------------

我为连接 level1、level2 和 level3 的区域创建了 id。在表 Offers_to_regions 中,我存储了报价和地区。在这里,我有 3 级 (020103) 的区域和 2 级 (0202) 的区域,用于提供 1。 使用这种设计,我遇到了如何查询每个区域的不同报价数量以及如何查询 level1、level2 和 level3 区域的报价的问题。

【问题讨论】:

  • 展示你目前所拥有的东西,然后问一些关于你目前所处位置的具体问题总是一个好主意。
  • 您使用的是哪种数据库?
  • @BertEvans - 我知道。我只是问,因为经过一天的思考,我没有创建任何解决方案。我只有区域层次结构。每个区域在级别 1 和级别 2 中都有 id 和对父区域的引用。有 3 个级别。我会尽快更新我的问题。

标签: hierarchical-data regions database-design


【解决方案1】:

嗯,有一种显而易见的方法是使用 id 指向这样的父级

CREATE TABLE Regions (
    region_id INT AUTO_INCREMENT PRIMARY KEY,
    parent_id INT,
    region_name VARCHAR(100) NOT NULL,
    FOREIGN KEY (parent_id) REFERENCES Regions(region_id)
);

但在您的情况下,这可能被视为一种反模式,因为通过层次结构查询并不那么容易(特别是如果级别数发生变化)

另一种方法可能是使用类似 Path Enumeration 的方法,您可以在其中存储类似于 unix 路径的层次结构路径。例如

CREATE TABLE Regions (
    region_id INT AUTO_INCREMENT PRIMARY KEY,
    path VARCHAR(100),
    region_name VARCHAR(100) NOT NULL
);

这将允许您像这样存储您的层次结构

---------------------------------------------
| region_id | path       | region_name      |
---------------------------------------------
| 1         | 1/         | subregion_1      |
| 2         | 1/2/       | subregion_11     |
| 3         | 1/2/3/     | region_111       |
| 4         | 1/2/4/     | region_112       |
---------------------------------------------

这样,在查询您的优惠表时(其中每个优惠都有一个对 region_id 的引用),并且在浏览时让我们说 subregion_1(id 为 1)的优惠,您的查询可能看起来像这样。

select Offers.SOME_COLUMN, ......
from Offers, Regions
where Offers.region_id = Regions.region_id
and   Regions.path like '1/%'

还有其他模式可以为您的分层数据建模,例如 Nested SetsClosure Table (maybe relevant),您可能也有兴趣研究.在选择/插入/删除性能方面,每个都有不同的优缺点

编辑:

我刚刚注意到您编辑了您的问题,而且优惠可能属于多个地区。以上可能需要调整以支持分配多个区域,但基本思想仍然可以应用。

【讨论】:

  • 但是如果报价将被添加到带有 subregion_1 (id=1) 的数据库中怎么办。此优惠应在所有分支 '1/%' 中可见,但在这种情况下,它将仅在 subregion_1 页面中可见?
  • 如果商品位于 suberion_1 中,是否应该在您浏览 region_111 和 subregion_11 和 subregion_1 时显示它?此外,如果报价在 region_111 中,它应该在 region_111、subregion_11 和 subregion_1 中可见吗?如果是这样的话,那么我认为不再需要等级制度了?!?!只需使用多对多关系来定义报价的可见性
  • 没错。这是为司机和乘客服务的。如果乘客在 area_1 中寻找司机,那么他会看到来自该 area_1 的司机的所有报价,这意味着他看到了来自 area_1 内较小区域的报价,但他没有看到来自 area_2 的报价,例如,因为这是不同的地理区域。当司机为 area_1 添加报价时,他的报价将在 area_1 下的所有子树中可见。但是当他在 area_1_1(area_1 内的子区域)中添加报价时,当乘客访问 area_1 站点时应该会看到报价,因为 area_1 包含 area_1_1。
  • 另请参阅我在 SO:What is the most efficient/elegant way to parse a flat table into a tree? 上解释关闭表的答案。要支持多个地区的优惠,您只需要一个多对多交叉表来引用优惠和地区。
  • @BillKarwin 您的 Closure Table 想法几乎不需要修改,这正是我所需要的。现在它的工作速度非常快。我的场景中的层次结构不会及时改变,因为它是省、区、市等国家/地区的区域,所以我将关闭表索引加载到 Mysql 缓存中,这是非常快速的解决方案:) 谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
相关资源
最近更新 更多