【问题标题】:What is important to keep in mind when designing a database?设计数据库时要记住哪些重要事项?
【发布时间】:2008-09-26 18:26:35
【问题描述】:

在设计数据库时要牢记哪些重要事项?

我不想限制您对我的需求的回答,因为我相信其他人也可以从您的见解中受益。但我正在为一个多客户社区驱动的网站规划一个内容管理系统。

【问题讨论】:

  • 我认为这是一个很好的问题,但认为标题可以澄清一下。如果您不同意,请随时回滚我的编辑。
  • 应该是社区维基

标签: database-design


【解决方案1】:

“规范化,直到它受伤;去规范化,直到它工作。”

【讨论】:

  • 以前从没听说过...很好!
  • 谁说的?无论如何,好答案,+1。
  • @Keng 这个问题有很多实际的答案,可惜他们没有像空话一样获得投票。
【解决方案2】:

(假设 OLTP)

数据结构的规范化。 (性能去规范化一般可以在需要的地方稍后进行)

http://en.wikipedia.org/wiki/Database_normalization

【讨论】:

    【解决方案3】:

    确保首先使用约束(CHECKNOT NULLFOREIGN KEYPRIMARY KEYDEFAULT)来确保只有正确的数据存储在数据库中。您总是可以购买更快的硬件,但您无法购买更多正确的数据。

    【讨论】:

      【解决方案4】:

      预先建立一致的命名标准。从长远来看,这将节省几分钟不必要的思考。 (这可能读起来很讽刺,但我是认真的。)

      不要缩写任何东西,除非它是非常常见的。不要将数据库变成车牌信息猜谜游戏。令人惊讶的是,一年后变得不明显。

      【讨论】:

        【解决方案5】:

        试着想象你将针对它执行的 SQL 查询。

        这很重要,因为你会做很多事情!

        【讨论】:

          【解决方案6】:

          我会记住一些事情。确保每个表都有唯一标识记录的方法(这样做可以节省数小时的痛苦)。规范化但不要加入大型多列自然键,除非您希望整个过程变慢。请改用在父表中自动生成的数字键。

          是的,考虑一下您需要运行的查询和报告类型。考虑可扩展性。看起来您在订单表中不需要超过 10 个产品列,但是当您需要 11 个时会发生什么。最好有一个订单表和一个订单详细信息表。

          确保所有数据完整性规则都已合并到数据库中。并非所有数据更改都发生在用户界面中,我不得不尝试修复太多严重混乱的数据库,因为设计人员认为将所有规则都放在 GUI 中是可以的。

          设计时要考虑的最关键的事情首先是如何确保数据完整性(如果数据没有意义,那么数据库就没有用),其次是如何确保性能。不要使用对象模型来设计关系数据库,除非你想要糟糕的性能。

          接下来最重要的是数据保护和安全。用户永远不应该直接访问数据库表。如果您的设计需要动态 SQL,他们将必须具有该访问权限。从通过 SQL 注入攻击之类的潜在黑客入侵的角度来看,这很糟糕,但更重要的是,它会为内部人员进行欺诈打开您的数据库。是否有需要加密数据的字段 (信用卡信息、密码和社会安全号码是永远不应未加密存储的项目之一)。您打算如何做到这一点以及您打算如何审核解密以确保人们在不需要查看数据时不会解密。有没有你必须经历的法律障碍(HIPPASarbanes Oxley 突然想到)?

          【讨论】:

            【解决方案7】:

            获取一本非常好的数据建模书籍 - 由真正的数据库开发人员编写,而不是试图教您如何在“现实世界”中完成数据建模的 .NET 开发人员。

            数据库设计的问题空间太大了,无法在这样的论坛中详细介绍。尽管如此,我还是给你一些个人建议:

            收听以上关于规范化的帖子。永远不要非规范化,因为您认为出于性能原因必须这样做。只有在遇到实际性能问题(理想情况下是在您的 QA 环境中,而不是在生产环境中)之后,您才应该进行非规范化。即便如此,请考虑可能有更好的方法来编写查询或首先改进索引。

            尽可能限制数据。列应尽可能为 NOT NULL。在任何应该使用的地方使用 CHECK 约束和 FOREIGN KEY。如果您不这样做,不良数据进入您的数据库并导致很多麻烦和特殊情况编程。

            在您真正开始设计表格之前,请仔细考虑您的数据。很好地了解您的流程将如何流动以及他们需要跟踪哪些数据。很多时候,你乍一看认为是一个实体,结果却是两个实体。例如,在我正在开发的系统中,之前的设计者创建了一个 Member 表,他们应用程序中的所有信息都是 Member 表的一部分。事实证明,成员可能想要更改其应用程序上的数据,但我们仍然需要跟踪原始应用程序的外观,因此应用程序实际上是它自己的实体,而成员是一个最初可能从应用程序。简而言之,做广泛的数据分析,不要只是开始创建表格。

            【讨论】:

            • 我喜欢您关于“永远不要进行非规范化,因为您认为出于性能原因必须这样做”的观点。
            【解决方案8】:

            由于现在已经有好几篇帖子提倡这一点,我再补充一点……

            不要陷入在所有表上都放置 ID 列的陷阱。现代数据库设计理论使用真正的主键有很多很好的理由,它们并不是严格的学术理由。我使用的数据库包含数百个表,其中许多是数百万行表,有超过 1000 个并发用户,并且使用真正的主键没有“崩溃”。

            在所有表上使用 ID 列意味着您必须执行多表连接才能遍历数据库,这会变得很麻烦。它还倾向于促进草率的数据库设计,甚至超出通常会导致重复行的问题。另一个问题是,在与外部系统打交道时,您现在必须传递这些 ID。

            代理 ID 有一些位置 - 类型代码表和概念表(例如,如果规则没有真实世界的标识符,则系统规则表可以使用 ID)。 IMO 到处使用它们是一个错误。

            这是一个长期存在的争论,但这是我对此事的看法,因为它的价值。

            【讨论】:

            • 这不是辩论。代理键用于使数据可维护。 “自然键”或“真实键”施加了奇怪的限制,有时反映现实世界,但有时反映关系模型。
            • 如果您如此傲慢地认为您的意见是唯一有效的意见,那只是“不是辩论”。正如我所说,我使用的数据库包含数百个表,并且数据很容易“维护”。施加的任何限制都是实际限制,或者您的模型是问题所在。
            • 问题不在于“一个聪明的人可以管理它”。显然,你的聪明,你可以管理它。问题是,如果没有放入不可变的代理键,会导致对数据库能做什么和不能做什么的奇怪的、古怪的限制。
            • 我两者都喜欢。对于几乎每个非联结表,我都有自动生成的代理键和唯一受约束的“自然”键。
            【解决方案9】:

            数据是永恒的。处理来来去去。

            让关系模型成为现实世界的高保真表示。这比什么都重要。

            处理将在数年内发生变化和发展。但是您的数据——以及数据模型——不能以同样的速度和同样的灵活性发展。您可以添加处理,但不能神奇地添加信息。您不想删除信息(但您可以忽略它。)

            让模型正确。图表中的实体和关系对于普通的非技术用户来说应该是合理的。即使是应用程序编程也应该简单、清晰和精确。

            如果您在模型方面遇到困难,请不要发明大而复杂的查询或(更糟糕的)存储过程来解决问题。程序上的变通方法是一个代价高昂的错误。了解您拥有什么,您想做什么,并应用 YAGNI 原则将事情精简到基本要素。

            【讨论】:

              【解决方案10】:

              我知道这已经说明了,但是规范化,规范化,规范化是关键。如果您觉得出于某种原因需要以非规范化格式存储数据,请不要这样做。这应该通过视图或在单独的报告数据库中处理。我的另一个主要建议是尽可能避免使用 text/ntext 字段。

              【讨论】:

                【解决方案11】:

                “数据库的拇指规则 - 总是失败!”

                示例: 如果您有一个 Customer 表,其中包含 Mailing Address 和 Shipping address 以及 Billing address 列...创建一个单独的 CustomerAddress 表,其中包含地址类型

                如果您有一个 CancellationDetails 表,其中包含 CancellationReason01、CancellationReason02、CancellationReason03.. 创建一个单独的 CancellationReason 表

                【讨论】:

                • 如果您有一个 CancellationDetails 表,其中包含 CancellationReason01、CancellationReason02、CancellationReason03...,那么您将遇到可怕的、可怕的混乱。我们的系统中已经有了其中的一些。
                【解决方案12】:

                务实。记住你的目标是什么,不要疯狂地创造不必要的复杂性。我有一些偏好:

                • 尽量减少表格数量
                • 更喜欢窄表而不是充满空值的宽表。
                • 归一化通常很好
                • 触发器通常非常痛苦

                但这些都是达到目的的手段(在很多情况下是矛盾的,需要仔细平衡),主要是让需求驱动设计。您对什么是独立实体、什么是另一个实体的一部分以及什么是猫粮(不是您关心其身份的任何东西)的选择完全取决于您的要求。

                【讨论】:

                • 我不一定不同意你的观点,但我很高兴地注意到你推荐几张桌子和小桌子。这可以概括为“存储少量数据”。我想这是一个很好的建议,因为它有助于避免冗余。 :-)
                • @Jeffrey:你说得对,肯定有一个平衡行为。诸如更多连接或更宽的表之类的东西?
                【解决方案13】:

                如果您要按主键以外的字段查找行,请确保为它们编制索引。

                【讨论】:

                • 好的提示,但不是真正的设计问题 IMO
                【解决方案14】:

                如果您有将要运行很多的查询,请将它们放入存储过程中。他们将几乎总是跑得更​​快。

                【讨论】:

                • 有这方面的证据吗?我认为这不是真的,我还没有找到任何可靠的基准。
                • 无论是否使查询运行得更快,这是一个很好的做法。
                【解决方案15】:

                是面向对象的语言吗?因此,请尝试在数据库之前对您的对象进行建模。这将帮助您专注于模型。

                【讨论】:

                  【解决方案16】:

                  尽可能多地预先了解要求。然后设计一个逻辑模式,只有在需求发生变化或迁移到完全不同类型的数据库时才需要更改,比如不使用 SQL 的数据库。然后将您的设计细化并扩展为考虑您的特定 DBMS 产品、您的体积、您的负载和您的速度要求的物理设计。

                  了解如何规范化,同时也要了解何时打破规范化规则。

                  【讨论】:

                    【解决方案17】:

                    我强烈赞同规范化至关重要,出于性能或其他可维护性原因,需要遵循战术去规范化。但是,如果您希望拥有的不仅仅是几张桌子,我想提出一个关于规范化的警告,随着表格数量的增加,这将使您的生活变得更加轻松。

                    需要注意的是,将每个表的主键设为单个数字列(适合您的 DB 风格)。在学术规范化中,想法是组合实体(表)的任何属性(列),以便您可以唯一地标识正在描述的内容(行)的实例,并且最终可以得到多列复合主键.因此,每当您将该复合键作为外键迁移到其他表时,您最终都会在引用它的 每个 表中复制这些多列。如果您只有六张桌子,这可能对您有用。但是当你比这大得多时,它很快就会分崩离析。

                    因此,不要使用多列复合主键,而是使用顺序数字主键,即使这种方法违背了一些严格的规范化教导。

                    【讨论】:

                      【解决方案18】:

                      确保在模型中编码尽可能多的元数据。只需查看数据模型,就应该可以推断出几乎所有业务规则或概念。

                      这意味着,请注意选择反映用户真实情况的名称(但不要害怕改变他们对真实情况的看法,如果这有助于模型)。

                      对数据库中的所有约束进行编码。不要依赖应用层只提供敏感数据。首先确保只有有意义的数据可以存在。

                      不要在模型中聚合数据。尽可能保持模型的原子性。即时聚合或将常规聚合作业运行到聚合表中。

                      在模式之间选择一个好的分区。一些分区与外键有关,而另一些则通过纯物理分隔。

                      【讨论】:

                        【解决方案19】:

                        不要使用大量列作为主键

                        【讨论】:

                        • 您需要在任何引用具有多列主键的表中的每一列。
                        • 这不一定是真的,因为您总是可以使用备用键作为外键(至少在 MS SQL 中)。将这些列带到主表中具有 FK 的表中也不是一件坏事。与您获得的其他优势相比,额外的空间通常并不重要。
                        • 在程序中,必须在代码中的变量中执行所有这些列有点乏味。
                        【解决方案20】:

                        请记住,标准化仅与您要建模的内容相关。也许您正在为您的域中的一组对象建模。也许您正在记录一系列事件,其中数据重复,因为相同的数据碰巧不止一次应用。不要把这两件事混为一谈。

                        【讨论】:

                          【解决方案21】:

                          尽可能使主键成为序列生成的数字。

                          【讨论】:

                            【解决方案22】:

                            我同意了解您的数据是好的和规范化的。

                            我建议的其他方法是将非常大的文本字段保存在单独的表格中。例如,如果您有一份合同,您可能希望将有关合同的大量信息保存在一个表中,但将法律(并且非常大)文档保存在单独的表中。只需将主表中的索引放入法律文件即可。

                            【讨论】:

                            • 为什么?我的意思是,不要告诉我你在做 SELECT * FROM Table :)
                            • 这个建议似乎依赖于实现(在数据库引擎端)。我认为它与 PostgreSQL 或 Oracle 无关,但不知道。在某处有一个这样的问题...
                            【解决方案23】:

                            我想说的重要一点是,结构可能会发生变化。所以不要把自己设计成一个角落。确保您所做的任何事情都会为您留下一些“空间”,甚至是有一天将数据迁移到不同结构中的途径。

                            【讨论】:

                              猜你喜欢
                              • 2023-03-21
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2010-11-11
                              • 2012-04-03
                              • 2011-07-26
                              • 1970-01-01
                              相关资源
                              最近更新 更多