单个 table vs 两个一对一相关的 table 性能
Single table vs two one-to-one related tables performance
假设我们要在关系数据库中存储以下数据:CountryName
、CapitalCityName
、CapitalCityPostCode
。让我们假设一个城市只有一个post代码。我们可以用一种简单的方式在 table 中实现它:
Countries
[PK]CountryId, CountryName, CapitalCityName, CapitalCityPostCode
或者我们可以将它以更规范化的方式排列成 1:1 关系中的 2 table:
Coutries
[PK]CountryId, CountryName, [FK]CapitalCityId
和
CapitalCities
[PK]CapitalCityId, CapitalCityName, CapitalCityPostCode, [FK]CountryId
这将如何影响性能?例如 - 如果我们需要列出所有国家的首都名称,在第一种情况下它会明显更快吗?我需要多少 records/columns 才能看到差异?
一般来说,如果有one-to-one对应,那么把数据拆分成两个table就没有什么优势了。如果没有冗余,你就不是"normalizing"数据。如果您需要按城市搜索,只需指定索引 CapitalCityName 列即可。您仍将获得搜索性能并消除必须为查询加入两个 table 的开销。
另一方面,如果每个城市有很多邮政编码(很常见),则需要单独的 table 来标准化数据并提供每个城市的邮政编码列表(或特定邮政编码的城市)。但这带来了一个新的问题:邮政编码可能不是唯一的:相同的代码可能在多个国家/地区重复出现,甚至出现 "twin cities" 共用一个邮政编码的情况。但这是另一个讨论的问题。
显然你可以看到第一个不是第三范式。在性能方面,正确规范化的 table 将与第一个示例中的平坦 table 相当,即使在处理 10s 和 100s 的数百万条记录时也是如此。尽管平面文件总是会稍微快一些,但如果相关性适当的话,数量是微不足道的。随着时间的推移,第一个问题变成了可扩展性。如果需要增长
,你就放弃了 unstable 基金会的一点性能提升
充其量只是边际差异。单身的table总会有微弱的优势;当您处理数亿条记录时,这会变得更加明显。但是有一些方法可以解决这个问题,将 table 划分为相关块,这样引擎就可以 multi-thread 收集结果并根据连接和过滤条件消除大量不需要的记录。
与任何其他开发一样,没有单一的灵丹妙药。规则总有例外;每个问题的上下文都很重要。然而,粗略的方法说,正常化,除非你知道永远不会有增长。 (从来没有很长时间!但也许系统有一个已知的保质期并且永远不会实现如此长期的存在。)
在上面的示例中,tables 用于 Country 和 CapitalCities,规范化不是很有帮助。一对一关系不会导致读取和更新数据时出现任何重复或复杂情况。如果需要 tables 的数据,例如国家和城市,国家的首都城市作为城市的 fk,这将很有帮助。
从两个 table 读取需要一个连接,这肯定比从单个 table 读取慢(不是很大)。对于数百条记录,所看到的差异为 10 到 15 毫秒。
假设我们要在关系数据库中存储以下数据:CountryName
、CapitalCityName
、CapitalCityPostCode
。让我们假设一个城市只有一个post代码。我们可以用一种简单的方式在 table 中实现它:
Countries
[PK]CountryId, CountryName, CapitalCityName, CapitalCityPostCode
或者我们可以将它以更规范化的方式排列成 1:1 关系中的 2 table:
Coutries
[PK]CountryId, CountryName, [FK]CapitalCityId
和
CapitalCities
[PK]CapitalCityId, CapitalCityName, CapitalCityPostCode, [FK]CountryId
这将如何影响性能?例如 - 如果我们需要列出所有国家的首都名称,在第一种情况下它会明显更快吗?我需要多少 records/columns 才能看到差异?
一般来说,如果有one-to-one对应,那么把数据拆分成两个table就没有什么优势了。如果没有冗余,你就不是"normalizing"数据。如果您需要按城市搜索,只需指定索引 CapitalCityName 列即可。您仍将获得搜索性能并消除必须为查询加入两个 table 的开销。
另一方面,如果每个城市有很多邮政编码(很常见),则需要单独的 table 来标准化数据并提供每个城市的邮政编码列表(或特定邮政编码的城市)。但这带来了一个新的问题:邮政编码可能不是唯一的:相同的代码可能在多个国家/地区重复出现,甚至出现 "twin cities" 共用一个邮政编码的情况。但这是另一个讨论的问题。
显然你可以看到第一个不是第三范式。在性能方面,正确规范化的 table 将与第一个示例中的平坦 table 相当,即使在处理 10s 和 100s 的数百万条记录时也是如此。尽管平面文件总是会稍微快一些,但如果相关性适当的话,数量是微不足道的。随着时间的推移,第一个问题变成了可扩展性。如果需要增长
,你就放弃了 unstable 基金会的一点性能提升充其量只是边际差异。单身的table总会有微弱的优势;当您处理数亿条记录时,这会变得更加明显。但是有一些方法可以解决这个问题,将 table 划分为相关块,这样引擎就可以 multi-thread 收集结果并根据连接和过滤条件消除大量不需要的记录。
与任何其他开发一样,没有单一的灵丹妙药。规则总有例外;每个问题的上下文都很重要。然而,粗略的方法说,正常化,除非你知道永远不会有增长。 (从来没有很长时间!但也许系统有一个已知的保质期并且永远不会实现如此长期的存在。)
在上面的示例中,tables 用于 Country 和 CapitalCities,规范化不是很有帮助。一对一关系不会导致读取和更新数据时出现任何重复或复杂情况。如果需要 tables 的数据,例如国家和城市,国家的首都城市作为城市的 fk,这将很有帮助。 从两个 table 读取需要一个连接,这肯定比从单个 table 读取慢(不是很大)。对于数百条记录,所看到的差异为 10 到 15 毫秒。