数据库设计中的不良做法:您是否犯了这些错误?

已发表: 2022-03-11

每当您作为开发人员被赋予基于现有代码的任务时,您都必须面对许多挑战。 其中一项挑战——通常是最苛刻的挑战——涉及理解应用程序的数据模型。

您通常会遇到令人困惑的表、视图、列、值、存储过程、函数、约束和触发器,这些需要很长时间才能理解。 而且,一旦他们这样做了,您就会开始注意到许多改进和利用存储信息的方法。

如果您是一位经验丰富的开发人员,您很可能还会注意到一开始可以做得更好的事情,即设计缺陷。

在本文中,您将了解一些常见的数据库设计不良做法,它们为什么不好,以及如何避免它们。

不良做法 1:忽略数据的目的

存储数据以供以后使用,目标始终是以最有效的方式存储和检索数据。 为了实现这一点,数据库设计者必须提前知道数据将代表什么,如何获取数据以及以什么速率获取数据,其操作量将是多少(即预期有多少数据),最后,它将如何使用。

例如,每天手动收集数据的工业信息系统与实时生成信息的工业系统具有不同的数据模型。 为什么? 因为与在同一时期管理数百万条记录相比,每月处理数百或数千条记录是非常不同的。 如果数据量很大,设计人员必须特别考虑以保持数据库的效率和可用性。

但是,当然,数据量并不是唯一需要考虑的方面,因为数据的用途也会影响规范化水平、数据结构、记录大小以及整个系统的总体实现。

因此,彻底了解您将创建的数据系统的用途会导致在选择数据库引擎、要设计的实体、记录大小和格式以及数据库引擎管理策略方面考虑。

忽略这些目标将导致设计在其基础上存在缺陷,尽管在结构和数学上是正确的。

不良做法 2:标准化不良

设计数据库不是一项确定性的任务。 两个数据库设计者可能会遵循给定问题的所有规则和规范化原则,并且在大多数情况下,他们会生成不同的数据布局。 这是软件工程的创造性本质所固有的。 但是,有一些分析技术在每种情况下都有意义,遵循它们是获得性能最佳的数据库的最佳方式。

一组数据的图像导致两种不同的布局

尽管如此,我们经常会遇到不遵循最基本的规范化规则而动态设计的数据库。 我们必须明确一点:每个数据库至少应该规范化为第三范式,因为它是最能代表您的实体的布局,并且其性能将在查询和插入-更新-删除记录之间得到最佳平衡.

如果您偶然发现不符合 3NF、2NF 甚至 1NF 的表格,请考虑重新设计这些表格。 您为此付出的努力将在短期内得到回报。

不良做法 3:冗余

与前一点非常相关,因为规范化的目标之一是减少它,冗余是另一种经常出现的不好的做法。

冗余字段和表对开发人员来说是一场噩梦,因为它们需要业务逻辑来保持相同信息的多个版本是最新的。 如果彻底遵循规范化规则,这是可以避免的开销。 尽管有时冗余似乎是必要的,但它必须仅在非常特殊的情况下使用,并清楚地记录在案,以便在未来的开发中考虑。

冗余的典型不良影响是不必要地增加数据库大小、数据容易出现不一致以及数据库效率降低,但更重要的是,它可能导致数据损坏。

不良做法 4:不良的参照完整性(约束)

参照完整性是数据库引擎为保持最佳数据质量而提供的最有价值的工具之一。 如果在设计阶段没有实现约束或约束很少,数据完整性将不得不完全依赖于业务逻辑,从而容易受到人为错误的影响。

错误做法 5:不利用数据库引擎功能

当您使用数据库引擎 (DBE) 时,您将拥有一个功能强大的软件来处理您的数据处理任务,这将简化软件开发并保证信息始终正确、安全和可用。 DBE 提供以下服务:

  • 提供快速有效的数据查看方式的视图,通常为查询目的对其进行反规范化,而不会丢失数据的正确性。
  • 有助于加快对表的查询的索引。
  • 无需编程即可帮助分析信息的聚合函数。
  • 如果发生意外情况,将全部执行并提交或取消(回滚)的事务或数据更改语句块,从而使信息始终处于正确状态。
  • 在执行事务时保持数据安全和正确的锁。
  • 提供编程功能以允许执行复杂数据管理任务的存储过程。
  • 允许复杂计算和数据转换的函数。
  • 有助于保证数据正确性和避免错误的约束。
  • 当数据上发生事件时有助于自动执行操作的触发器。
  • 在后台运行的命令优化器(执行计划器),确保每个句子都以最佳状态执行,并为将来的情况保留执行计划。 这是使用视图、存储过程和函数的最佳理由之一,因为它们的执行计划永久保存在 DBE 中。

不了解或忽略这些功能将使开发走上一条极其不确定的道路,并且肯定会导致错误和未来的问题。

不良做法 6:复合主键

这是一个有争议的观点,因为现在许多数据库设计人员都在谈论使用整数 ID 自动生成的字段作为主键,而不是由两个或多个字段组合定义的复合字段。 这目前被定义为“最佳实践”,我个人倾向于同意它。

复合主键的图像

然而,这只是一个约定,当然,DBE 允许定义复合主键,许多设计者认为这是不可避免的。 因此,与冗余一样,复合主键是一种设计决策。

但是请注意,如果您的具有复合主键的表预计会有数百万行,则控制复合键的索引可能会增长到 CRUD 操作性能非常下降的程度。 在这种情况下,最好使用一个简单的整数 ID 主键,其索引将足够紧凑,并建立必要的 DBE 约束以保持唯一性。

错误做法 7:索引不佳

有时,您将拥有一个需要按多列查询的表。 随着表的增长,您会注意到这些列上的 SELECT 速度变慢。 如果表足够大,从逻辑上讲,您会认为在用于访问该表的每一列上创建一个索引,但几乎立即发现 SELECT 的性能有所提高,但 INSERT、UPDATE 和 DELETE 的性能下降了。 这当然是因为索引必须与表保持同步,这意味着 DBE 的大量开销。 这是一个典型的过度索引情况,您可以通过多种方式解决; 例如,在与用于查询表的主键不同的所有列上只有一个索引,将这些列从最常用到最少排序可能在所有 CRUD 操作中提供比每列一个索引更好的性能。

另一方面,众所周知,在用于查询的列上没有索引的表将导致 SELECT 的性能不佳。

此外,索引效率有时取决于列类型; INT 列上的索引显示出可能的最佳性能,但 VARCHAR、DATE 或 DECIMAL(如果有意义的话)上的索引效率不高。 这种考虑甚至会导致重新设计需要以尽可能高的效率访问的表。

因此,索引总是一个微妙的决定,太多的索引可能和太少一样糟糕,因为要索引的列的数据类型对最终结果有很大的影响。

不良做法 8:糟糕的命名约定

这是程序员在面对现有数据库时经常遇到的问题:通过表和列的名称了解其中存储了哪些信息,因为通常没有其他方法。

表名必须描述它包含的实体,每个列名必须描述它代表的信息。 这很容易,但是当表必须相互关联时,它就开始变得复杂了。 名称开始变得混乱,更糟糕的是,如果命名约定与不合逻辑的规范混淆(例如,“列名必须为 8 个字符或更少”)。 最后的后果是数据库变得不可读。

因此,如果期望数据库能够持续并随着它支持的应用程序而发展,那么命名约定总是必要的,这里有一些指导方针来建立一个简洁、简单和可读的命名约定:

  • 对表名或列名大小没有限制。 最好有一个描述性的名称,而不是一个没人记得或理解的首字母缩写词。
  • 相同的名称具有相同的含义。 避免具有相同名称但具有不同类型或含义的字段; 这迟早会令人困惑。
  • 除非必要,否则不要多余。 例如,在“Item”表中,不需要有“ItemName”、“PriceOfItem”或类似名称的列; “名称”和“价格”就足够了。
  • 当心 DBE 保留字。 如果要将列称为“索引”,这是一个 SQL 保留字,请尝试使用不同的名称,例如“IndexNumber”。
  • 如果坚持简单的主键规则(自动生成单个整数),请在每个表中将其命名为“Id”。
  • 如果连接到另一个表,将必要的外键定义为一个整数,命名为“Id”,后跟连接表的名称(例如,IdItem)。
  • 如果命名约束,请使用描述约束的前缀(例如,“PK”或“FK”),后跟所涉及的一个或多个表的名称。 当然,谨慎使用下划线(“_”)有助于提高可读性。
  • 要命名索引,请使用前缀“IDX”,后跟表名和索引的列。 此外,如果索引是唯一的,则使用“UNIQUE”作为前缀或后缀,并在必要时使用下划线。

互联网上有许多数据库命名指南,它们将更加清楚地说明数据库设计的这一非常重要的方面,但有了这些基本的,你至少可以得到一个可读的数据库。 这里重要的不是您的命名准则的大小或复杂性,而是您遵循它们的一致性!

一些最后的评论

数据库设计是知识和经验的结合; 自早期以来,软件行业已经发展了很多。 幸运的是,有足够的知识可以帮助数据库设计人员获得最佳结果。

互联网上有很好的数据库设计指南,也有数据库设计中要避免的不良做法和事情。 只需选择并坚持下去。

而且,别忘了,只有通过实验、错误和成功,你才能学到东西,所以现在就开始吧。