【问题标题】:mysql database chained tables denormalizationmysql数据库链表非规范化
【发布时间】:2011-11-12 10:10:04
【问题描述】:

我遇到了 db 非规范化的设计问题。
我正在制作一个相对较大的数据库,需要尽可能地对其进行优化。

这是一个非常简化的问题模型。
图片中的所有表都是链式的,并且使用标准化数据库来获取例如来自特定国家/地区的所有用户,我必须加入所有表。即 cca 250 个国家 x cca 12000 个城市 x cca 625000 个地区 x ?地址 x ?用户...总之就是加入很多,需要很长时间。

我想要做的是使country_id 在user 表中变得多余,这样我就可以在没有任何连接的情况下获得相同的查询。

问题是,在这种模型中保持一致性的最佳做法是什么(顺便说一句。使用 MySql)?

一种可能最快的方法是在插入/更新/删除数据时确保应用程序级别的一致性。

其他是存储过程,我真的看不出有什么好处。它们仅在直接调用时才确保一致性。如果您想在没有过程的情况下进行一些更改,则会破坏一致性。

我也一直在研究触发器...不太确定如何实现它,以及我会在性能方面获得多少收益。

无论如何,最好确保数据库级别的一致性。

有什么建议吗?

【问题讨论】:

    标签: mysql sql database database-design denormalization


    【解决方案1】:

    假设您没有尝试对所有数据进行非规范化,加入并不是真的很多。

    另一方面,大多数人只有一个地址表,或者(喘不过气!)将地址信息保存在用户表中。您希望支持多少个国家/城市,以及多少用户?

    【讨论】:

    • 正如我所说,它是一个简化模型。需要这种结构。至于记录的数量,您必须能够从世界上几乎任何地方进行注册,因此帖子中的数字几乎可以召唤它。有多少用户,很难预测......无论如何它必须能够处理几十万用户。还要提一下,很多查询都是针对特定国家/地区的,所以一次又一次地加入一切似乎太多了
    • 然后在 users 表中有一个 countryID、一个 StateID 和一个 ... 等等。除非您出于某些复杂的业务目的需要层次结构,否则我强烈建议您避免使用它。
    • 好的,但问题是如何确保一致性是这样一个模型,而不是真正使用与否
    • 数据一致性不应该有任何问题。如果您正在谈论保持城市和国家之间的一致性,您当然可以在您的国家/地区的城市表中拥有一个 FK,但您需要确定这是否有必要。执行这类事情的业务要求是什么?
    • 如果你坚持给我们一个简化的模型,你应该准备好接受简化的回应。
    【解决方案2】:

    图片中的所有表都是链式的,并且具有标准化 数据库来获取例如来自特定国家的所有用户我 必须加入所有表格。

    您必须连接所有表格,因为您使用代理键(ID 号),而不是因为表格已“规范化”。使用 id 号码之类的代理键与规范化无关。

    自然键和外键约束是您解决问题所需要的一切。

    了解其工作原理的最简单方法是从完整数据开始,然后完全倒退。假设所有数据都是正确的。

    addr_id  street           street_num       region    city          country
    --
    1        Babukiaeeva      3a               10000     Zagreb        Croatia
    2        Riva             16               51000     Rijeka        Croatia 
    3        Andrije Hebranga 2-4              10000     Zagreb        Croatia
    4        Andrijeviaeeva   2               110000     Zagreb        Croatia
    

    要记录诸如“地区 '10000' 与国家 '克罗地亚' 中的城市 '萨格勒布' 相关联”之类的事实,请创建一个新表,并从该查询中填充它。

    SELECT DISTINCT region, city, country from addresses;
    

    表格将如下所示。

    Table: regions
    Primary key: {region, city, country}
    
    region   city      country
    --
    10000    Zagreb    Croatia
    51000    Rijeka    Croatia
    110000   Zagreb    Croatia
    

    然后设置一个外键引用。

    ALTER TABLE addresses 
    ADD CONSTRAINT FOREIGN KEY        (region, city, country) 
                   REFERENCES regions (region, city, country);
    

    要记录“城市'萨格勒布'在国家'克罗地亚'”这样的事实,请创建一个新表,并从此查询填充它。

    SELECT DISTINCT city, country from regions;
    

    表格将如下所示。

    Table: cities
    Primary key: {city, country}
    
    city      country
    --
    Zagreb    Croatia
    Rijeka    Croatia
    

    然后设置一个外键引用。

    ALTER TABLE regions 
    ADD CONSTRAINT FOREIGN KEY       (city, country) 
                   REFERENCES cities (city, country);
    

    对国家/地区重复。表国家、城市和地区都是关键,所以它们在 5NF 中。 (它们不能有任何非键依赖,因为它们没有非键列。)在大区域的上下文中,像整个欧洲一样,地址表很可能也在 5NF 中。

    就查询性能而言,它可能会围绕您当前的架构运行,因为它不需要连接。

    您可能想要使用ON UPDATE CASCADE;不过,您可能不想要级联删除。

    【讨论】:

    • 这是一种完全冗余的方法。我认为出于性能原因最好不要使用复合键。但是,我仍然不相信这是做到这一点的方法,因为它复制了所有/任何地方。我认为最终不适合物化视图方法
    • “冗余”是关系理论中的技术术语;它与存储外键没有任何关系。 (这就是外键的用途。) 这些 复合键消除了所有 连接。在大多数情况下,这种模式的执行速度比 3 或 4 个连接要快。我已经运行过这样的测试,它的执行速度提高了 200 倍。在提交到此架构或物化视图之前,您应该测试性能。
    • 是的,它们消除了连接,这是对的……但是它们复制了大量数据(每个表中的所有“较低”键),并且存在持久性问题。组合键的性能较低(至少在 MySql 中),所以我认为最好引入一个新的递增 ID,并使组合唯一。但是,无论如何:我更喜欢物化视图方法。仍然存在持久性问题,但至少“原始”表中没有冗余
    • 复合键在连接中的性能稍慢。但是,当您在架构中使用自然键时,您会消除 所有 连接。而外键是keys;这就是您应该存储在关系数据库的多个表中的内容。如果有什么值得称为“完全冗余”的话,那就是物化视图,它复制了数据的每一位。 (而且 MySQL 不支持物化视图。)模拟两种模式,生成 1000 万行数据,并测试性能和磁盘空间使用情况。
    • “我所指的真正优势是保持“原始”模型干净且没有冗余。只需删除视图,所有非规范化都消失了,剩下的是 3NF 模式。”但是另一个模式没有要删除的非规范化,它在 5NF 中。无论如何,您的观点不会简单地重现决赛桌吗?似乎是一个奇怪的决定。
    【解决方案3】:

    首先 - 它真的太慢了​​吗? 你试过了吗? 您是否有一个应用程序可以转储所有用户(为什么?),或者您是否时不时地获取单个/少数用户。由于您在所有这些 id 上都有主键,因此检索不应该那么慢,毕竟在后台有一个 B-tree。

    其次,我不会在街道 number 级别上进行标准化,您几乎不会从中获得任何好处,并且您最终可能会在用户和用户之间建立几乎 1:1 的关系一个地址。因此,将您的门牌号移至客户端,或者您甚至可以将整个地址表移至用户。我可能会将区域表也移动到客户端(这些是城市区域?)并最终得到用户、城市和国家/地区表。

    然后你会有两个连接,如果这仍然太慢,你可以在用户中放置多余的国家键(或者,因为我们正在反规范化 - 国家名称)。我会使用 triggers 来保持完整性,更准确地说,您必须编写:插入和更新触发器(仅当 regionId/cityId 更改时才需要触发更新),以及国家/地区的更新触发器(如果您在用户表中有国家名称)万一国家名称更改。

    在性能方面,您不会获得收益,但会因触发器而失败,但我认为用户表上的插入和更新不会那么频繁,以至于您根本不会注意到它。

    最后,由于您没有详细解释您的(网络?)应用程序的性质和大小,只是提醒您,您可能还想考虑/包括关系数据库之外的其他优化技术(缓存、no-sql dbs 等)。

    【讨论】:

    • 地址用于一些事情,而不仅仅是用户......所以我不能将它移动到用户表中。是的地区是城市地区。它们也应该保持独立,因为它们被用于很多地方(比城市更多)。好的,我正在使用带有上述物化视图方法的触发器。
    猜你喜欢
    • 1970-01-01
    • 2011-09-24
    • 2011-12-16
    • 2013-07-17
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2016-07-23
    相关资源
    最近更新 更多