mysql数据库链式表非规范化

时间:2011-09-07 18:39:49

标签: mysql sql database database-design denormalization

我有db denormalization的设计问题 我正在建立一个相对较大的数据库,需要尽可能地优化它。

这是一个非常简化的问题模型 图片中的所有表都是链接的,并且使用规范化的数据库来获取来自特定国家/地区的所有用户,我必须加入所有表。那是cca 250个国家x cca 12000个城市x cca 625000个地区x?地址x?用户......简而言之,这需要很长时间才能加入。

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

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

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

其他是存储过程,我真的看不出任何优点。只有直接调用它们才能确保一致性。如果您想在没有程序的情况下进行一些更改,则一致性会中断。

我一直在关注触发器...不确定如何实现它,以及我将在性能上获得多少。

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

有什么建议吗?

Sample model

3 个答案:

答案 0 :(得分:6)

  

图片中的所有表格都是链接的,并带有规范化   例如,获取来自特定国家/地区的所有用户的数据库   必须加入所有表格。

您必须加入所有表,因为您使用代理键(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;但是,你可能想要级联删除。

答案 1 :(得分:1)

首先 - 它真的太慢了​​吗? 你试过吗? 你有一个转储所有用户的应用程序(为什么?),或者你偶尔提取一个/少数用户。由于您在所有这些ID上都有主键,因此检索速度不应该那么慢,毕竟背景中有B树。

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

然后你有两个连接,如果仍然太慢,你可以在用户中放置多余的国家/地区密钥(或者,因为我们正在进行非规范化 - 国家/地区名称)。我将使用触发器来保持完整性,更准确地说,您必须编写:插入和更新触发器(更新只需在regionId / cityId更改时触发),以及国家/地区的更新触发器(如果如果国家/地区的名称发生变化,您可以在用户表中使用国家/地区名称。

性能方面,你不会获得,但会失败,但是我认为用户表上的插入和更新不是那么频繁,你根本就没有注意到它。

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

答案 2 :(得分:0)

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

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