【问题标题】:Assistance with Database Schema (platform independent)协助数据库模式(独立于平台)
【发布时间】:2017-12-13 18:53:24
【问题描述】:

我有一个意见问题,但同时可能有一个正确的答案。我正在尝试开发一套产品,并希望确保因为我自己在做,所以我第一次就做对了。我多次重写了架构,每次都认为它更好。然后我可能会遇到一些新想法,它要么需要在架构上进行大量工作,要么会破坏我的架构。

在大学里,我学会了“合理化”(我认为这是他们使用的词,可能有点离题)一个数据库,有 5 个级别。据我记得,3 级是最常见的。我知道这种做法是为了确保数据不会重复,为此,您必须将表分解为较小的表。并且取决于你打破它的程度,级别越高。好吧,我不知道我是否想要最高级别,但我知道我希望它尽可能高效。我已经使用了 4 年的 SQL Server 2000/2005/2008 和 2 年的 Oracle,使用 Informix 大约 6 个月(5 多年前),在这里或那里使用 mySQL 和大约 6 个月的 Access。我的首选是 SQL Server,但我希望架构在任一平台上都一样高效。

这是一些表的伪模式布局,然后我将解释我想要做什么。

Manufacturers
  ManufacturerID (Identity)
  ManufacturerName
  ManufacturerStreetAddress
  ManufacturerZipCodeID
  ...

ZipCodes
  ZipCodeID (Identity)
  ZipCode
  ZipCodeStateID
  ...

States
  StateID (Identity)
  StateName
  StateAbbreviation
  ...

Cities
  CityID (Identity)
  CityName
  CityStateID
  ...

我很抱歉它只是一个伪模式,但这就是我现在所拥有的,因为我正在休息时在纸上进行设计,但在我走得太远之前有一个问题。我想做的是确保一切都正确地相互联系。我的信念是邮政编码属于一个州和一个城市,但没有一个城市属于任何一个邮政编码,它可能有很多。如果我将邮政编码放在制造商表中,我希望能够获得州和城市。但我不想在其他表中多次使用任何 ID。我的意思是在 ZipCodes 和 Cities 中拥有 StateID 的次数可能太多了。一个州可以有多个同名城市,多个州可以有同名城市。但我不确定我是否想要一个 CityNames 表,然后是一个 CityStates 表(CityNameID 和 StateID)。我很清楚有一些位置数据库可供购买,也许有些是免费的,我可以使用而且不必担心这一点。但是,我想努力理解这一点,因为我相信它会在未来帮助我进行架构设计,而且还因为如果需要更改任何内容,我希望拥有布局的可定制性。

问题:

  1. 这种伪模式看起来是正确的还是会更好(意见)?
  2. 它是否被称为“合理化”数据库,或者其他什么(将投票支持正确答案)?还有多远(意见)
  3. 还有一个用户表和其他包含地址的表(Teams、Capitols 等),如果理论上是正确的,那么伪模式也是这样的数据库的好计划(意见)?

感谢大家的宝贵时间,我会投票赞成任何彻底和连贯的答案。数据库专家或具有多年数据库经验的人优先,但我会听取所有答案。另外,我不确定这是否应该是一个社区 wiki,但我现在没有将它标记为一个。谢谢。

更新:另外,我忘了提到我知道“合理化”数据库需要连接,有时还需要子查询。我通常会滥用 LEFT OUTER JOIN,但是将这些表绑定在一起以显示地址而不是执行 4 个不同的查询的最有效方法是什么?谢谢。

更新:好的,现在这可能过于规范化或不够规范化或根本没有,但是你们能告诉我你是否更喜欢这个伪模式吗?

Manufacturers
  ManufacturerID (Identity)
  ManufacturerName
  ManufacturerStreetAddress
  ManufacturerCCSZID --CCSZ (Country, City, State, Zip), needs a better name
  ...

ZipCodes
  ZipCodeID (Identity)
  ZipCode
  ...

States
  StateID (Identity)
  StateName
  StateAbbreviation
  ...

Cities
  CityID (Identity)
  CityName
  ...

Countries
  CountryID (Identity)
  CountryName
  CountryAbbreviation
  ...

CountryCityStateZipCodes
  CountryCityStateZipCodeID (Identity)
  CCSZCountryID
  CCSZStateID
  CCSZCityID
  CCSZZipCodeID

要获得地址,它看起来像:

SELECT  M.ManufacturerStreetAddress,
        CN.CountryName,
        CN.CountryAbbreviation,
        S.StateName,
        S.StateAbbreviation,
        C.CityName,
        Z.ZipCode
FROM Manufacturers M
LEFT OUTER JOIN CountryCityStateZipCodes CCSZ ON CCSZ.CountryCityStateZipCodeID = M.ManufacturerCCSZID
LEFT OUTER JOIN Countries CN ON CN.CountryID = CCSZ.CCSZCountryID
LEFT OUTER JOIN States S ON S.StateID = CCSZ.CCSZStateID
LEFT OUTER JOIN Cities C ON C.CityID = CCSZ.CCSZCityID
LEFT OUTER JOIN ZipCodes Z ON Z.ZipCodeID = CCSZ.CCSZZipCodeID

或者也许你们知道编写该查询的更好方法。但无论如何,这看起来比第一个模式更好吗?

【问题讨论】:

  • 你不能那样做,邮政编码不只属于一个城市。在农村地区,他们可能在一个邮政编码中有多个小镇。当然,城市也可能有多个邮政编码。将整个地址存储在制造商地址表中。
  • 嗯,据我了解,当我将包裹送到邮局时,他们并不像担心邮政编码那样担心城市/城镇。这就是为什么我想知道将城市与多个邮政编码联系起来的最佳方式,反之亦然。我相信可以做到,我确定已经做到了,我只是想知道怎么做。
  • 另外,我不想存储整个地址的主要原因是因为我想提供一种简单的方法来搜索特定城市中的制造商、用户或任何对象, zipcode、state 等。使用 ID 比解析整个地址要容易得多。除非整个地址是指邮政编码、州、城市等列。
  • 好的,谢谢。当我阅读你们的答案时,我记得在学校听到过“Normal Form 3”。珍惜吧。
  • 邮政编码是唯一的,请将其作为邮政编码表中的主键。州缩写也是如此,因此我建议将它们用作州表中的主键。

标签: database-design cross-platform database-schema


【解决方案1】:

我一直听说它称为“标准化”,但我们谈论的是同一件事。

最简单的方法可能是将城市、州和邮编合并到一张表中。您甚至可以考虑使用邮政编码本身作为密钥,尽管我可以想到您想要避免这种情况的两个原因:

  1. 东北各州有邮政编码 以 0 开头,这将是 如果您将邮政编码设为 a,则会被截断 数值字段。
  2. 如果您使用邮政编码作为密钥,则不能有多个该邮政编码 多个城镇的时间。喜欢你 说,邮局更关心 关于zip比镇名。 但是这个设置会限制你 从那些人身上搜索 之后的城镇。

以后要按城市、州或邮编搜索,只需将此表加入到制造商表中即可。您可以使用 INNER JOIN - 除非 Manufacturers 表中的字段 ManufacturerZipCodeID 为空,在这种情况下,您还需要 LEFT JOIN 来显示这些字段。

【讨论】:

  • 感谢您的回答。我知道它以“alization”结束,哈哈。是的,我什至没有考虑邮政编码中的 0,即使我可以轻松地使用代码或视图以 0 开头。但是,手动查看数据库会令人困惑。我将手动放入所有内容,因此任何制造商都不应该有一个空邮政编码,但这是很好的知识(关于连接)。不过,我将不得不就跨越州界的拉链与邮局联系,因为我也没有考虑过。谢谢。
【解决方案2】:

我对您的设置方式没有太大意见。邮政编码中的州 ID 可能很危险 - 得知有跨州边界的邮政编码并不会让我感到惊讶,但我不确定。

您将通过将州、城市和邮政编码存储在单独的表中来执行大量连接,但是在处理存储地址而没有一致性措施的数据库之后,这比几次连接更像是一场噩梦。例如,您最终会得到“NY”和“ny”以及“Ny”和“New York”和“NewYork”。所以我认为从长远来看,为州、城市和邮编设置单独的表格会有所回报。

【讨论】:

  • 是的,我就是这么想的。我在等待答案时也在考虑,但现在决定反对,如果数据库中没有,允许用户输入他们的城市、州、邮编等。这样它就可以自己构建,而我不必手动完成所有操作。我可以给自己编辑能力,但同时,它可能需要我自己投入的时间。而且我相信可能会有一些跨越州界的邮政编码。不过感谢您的回答。
【解决方案3】:

我不是数据库专家,但在我看来,给定的伪模式似乎不正确。这是解释。从问题中得知的事实是:

  1. 一个州可以有多个城市。
  2. 状态是唯一的
  3. 一个城市可以有多个邮政编码
  4. 城市名称可能与另一个城市名称相同。
  5. 邮政编码是唯一的

首先,写下唯一性。所以我们构建了这两个原始表:

STATE
---
State ID (PK)
State Name

ZIP
---
Zip ID (PK)
Zip Code (NK)

然后,出现了一个逻辑问题。知道 Zip ID,我们将如何检索城市 ID?要回答这个问题,我们需要提供 Zip 和 City 之间的链接。这个链接应该放在哪里?它不在 City 表中,因为从 Fact#3 我们知道一个城市可以有许多不同的邮政编码。所以它必须在 ZIP 表中。这是我们下一个版本的 ZIP 表:

ZIP
---
Zip ID (PK)
Zip Code (NK)
City ID (FK)

现在,由于我们可以从 Zip“移动”到 City,我们将讨论 City 表。城市名称可以与其他名称相同。所以我们不需要强制它(城市名称字段)是唯一的。所以这是我们第一个版本的 City 表:

CITY
----
City ID (PK)
City Name

同样,同样的逻辑问题出现了。我们如何搬到州知道一个城市?必须在这两个表之间的某处创建链接。同样,知道事实#4 并不能保证城市名称的唯一性。链接必须放在 City 表上。所以这是我们下一个版本的城市表:

CITY
---
City ID (PK)
City Name
State ID (FK)

通过这个链接,我们可以正确地检索状态。总的来说,我们可以通过 City ID(在 Zip 表中提供)从 Zip 移动到 City,我们可以继续通过 State ID(在 City 表中提供)从 City 移动到 State。

从数据库的角度来看,合理化数据库是好的,但从编程的角度来看可以被认为是“邪恶的”。因为它促使程序员编写越来越多的类。毕竟,“太远”可以定义为“表变得不合理”。 City Name 表似乎不合理,因为它是一个属性,而不是一个实体。如果我的数据库分析师创建了这样一个不合理的表,我会很乐意将其标记为“太远” :) 另一方面,过度合理化数据库会极大地影响数据库性能。根据我的经验,它会使查询运行速度变慢。

关于其他问题,如用户、团队、国会大厦等。我现在不能说什么,因为我还没有看到问题。

【讨论】:

  • +1 表示彻底。其他表之间不会有太大区别。他们也会有地址,但我想将他们的地址与上述表格联系起来,就像制造商一样。但是,我试图找到一个邮政编码是否由两个州共享的示例。我知道我妻子在阿拉巴马州托尼有家人,托尼就在田纳西州边境的另一边,所以他们共享城市,我不确定邮编。如果是这样,则该邮政编码需要有两个条目,每个城市 ID 一个。
  • 我想问每个人的一个问题是,如果查询运行慢 15 毫秒,甚至慢 2 秒,这是否太贵了?或者这对用户来说也是一个问题?我猜你们也需要知道数据库的大小。
  • 设计数据库时的一般规则是尽可能规范化。然后,如果您看到会出现性能问题的区域,请出于性能原因对这些区域进行非规范化处理。但是,您不应该对性能进行猜测和非规范化,因为您认为某些事情会成为问题。当测试证明这样做可以提高性能时,您应该测试您的假设并去规范化。
  • 谢谢,我也是这么想的。我真的很感谢所有的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 2010-10-08
  • 1970-01-01
  • 2012-12-19
相关资源
最近更新 更多