21CTO导读:了解良好的数据库设计,对于确保数据准确性、一致性和完整性以及数据库高效、可靠和易于使用都至关重要。
本文将带领大家了解一些常见的数据库设计不良实践、它们为何不好以及如何避免它们的发生。
不良做法之一:忽视数据的目标
存储数据是为了稍后在应用程序中使用。其核心目标是始终以最有效的方式存储和检索数据。为了达到这一目的,数据库的设计者必须提前知道数据将代表什么,如何获取数据以及用什么速率获取,其操作数量将是多少(即预期有多少数据)。然后最后,它将如何被使用或调用。
例如,每天手动收集数据的系统不会与实时生成信息的工业系统使用相同的数据模型。
这是为什么?因为每月处理数百或数千条记录与同时管理数百万条记录有很大不同。如果数据量很大,设计者必须特别考虑,以便保持数据库的效率和可用性。
当然,数据量并不是唯一需要考虑的方面,因为数据的用途还影响规范化水平、数据结构、记录大小以及整个系统的总体实现。
因此,彻底了解即将创建的数据系统的用途有助于选择数据库引擎、要设计的实体、记录大小和格式,以及数据库引擎管理等策略。
尽管在结构和数学上是正确的,但忽视这些目标将导致设计在基础上存在缺陷。
不良做法之二:规范化遵守不佳
设计数据库并不是一项确定性任务。
两个数据库设计者可能会遵循给定问题的所有规则与规范化原则,并且在大多数情况下他们会生成不同的数据布局,这是软件工程独有的创造性本质。
有一些数据库性能分析在各种情况下都有意义,遵循这些技术是获得最佳性能数据库的最佳实践。
在现实中,我们经常面临设计不佳的数据库,即不遵循最基本的规范化规则(范式)而即时设计的数据库。数据库设计者必须要明确这一点:每个数据库至少应该符合规范化,即第三范式,因为它的布局最能代表你的实体,并且它的性能在查询和插入更新删除记录之间达到最佳之平衡。
如果你偶然发现不符合3NF、 2NF 甚至 1NF 的数据表,请考虑重新设计这些表。相信你为此付出的努力,将在短期内得到回报。
不良做法之三:冗余
与上面一点非常相关,由于规范化的目标之一是精简,因此冗余是经常出现的另一种非规范的做法。
冗余字段和表对于开发人员来说,初期是一个方便之举,而之后将可能是一场噩梦。—— 因为它们需要各种业务逻辑来使相同信息的多个记录版本保持最新。
如果彻底遵循规范化规则,能够避免这些不必要的开销。尽管有时冗余似乎是必要的,但它必须仅在非常特殊的情况下使用,并请你清楚地记录下来,以便在未来的开发中予以考虑。
冗余的典型不良影响,是数据库大小不必要的增加、数据容易不一致以及数据库效率降低,但更更重要的是,它极可能导致数据坏掉。
不良做法 4:不良引用完整性(约束)
参昭完整性是数据库引擎为保持最佳数据质量而提供的有价值的工具之一。如果从设计阶段就没有实现约束或实现很少的约束,则数据完整性将不得不完全依赖于业务逻辑,从而像上面所说的一样,容易出现人为错误。
坏习惯 5:不利用数据库引擎功能
当我们使用数据库引擎(DBE) 时,你就拥有了一个用于数据处理任务的强大软件,它将简化软件开发,并保证信息始终正确、安全和可用。
DBE 将为开发者提供以下服务:
-
提供快速有效的方式查看数据视图,通常出于查询目的对其进行非规范化,而不会丢失数据的正确性。
-
有助于加快表索引查询速度。
-
无需编程,即可帮助分析信息的聚合函数。
-
如果发生意外情况,事务或数据更改语句块都会被执行并提交或取消(回滚),从而使信息保持持久正确的状态。
-
在执行事务时,保持数据安全与正确的锁。
-
可以开发复杂的数据管理任务的存储过程。
-
允许复杂计算与数据转换的函数。
-
有助于保证数据正确性并避免错误的约束。
-
当数据发生事件时,帮助自动执行操作的触发器。
-
命令优化器(执行计划器)在后台运行,确保每个命令都以最佳状态执行,并为将来的情况保留执行计划。
这一条是使用视图、存储过程和函数的最佳理由之一,因为它们的执行计划永久保存在 DBE 中。
忽视这些特点将使开发走上一条曲折的道路,并且肯定会出现错误和未来的维护问题。
坏习惯 6:复合主键
这是一个有争议的观点。现在有许多数据库设计者都在谈论使用整数 ID 自动生成的字段作为主键,而不是由两个或多个字段的组合定义的复合字段。这是目前数据库设计最佳实践之一,就我个人而言,我倾向于同意。
然而,这只是一个约定,而数据库引擎允许定义复合主键,许多设计人员认为这是不可避免的。因此与冗余一样,复合主键也是一个设计决策。
但请注意的是,如果有复合主键的表有数百万行,则控制复合键的索引可能会增长到 CRUD 性能严重下降的问题。在这种情况下,最好使用简单的整数 ID 做为主键,其索引足够紧凑,并建立必要的 DBE 约束来保持其唯一性。
坏习惯七:糟糕的索引
有时,你将有一个需要按许多列进行查询的表。随着表的增长,你会发现到这些列上的 SELECT 速度变慢。如果表足够大,从逻辑上讲,你会认为在用于访问该表的每一列上创建索引,结果立即发现 SELECT 的性能提高了,但 INSERT、UPDATE 和 DELETE 的性能却下降了。
这是因为索引必须与表保持同步,这意味着 DBE 的巨大开销。这便是过度索引的典型案例,我们可以通过多种方式解决;例如,与用于查询表的主键不同的全部列上只有一个索引,按从最常用到最少的顺序对这些列进行排序,可能会在所有 CRUD 操作中提供比每列都建一个索引能获得更好的性能。
众所周知,如果表中用于查询的列没有建立索引,则会让 SELECT 性能不佳。
此外,索引效率有时取决于列类型;INT 列上加索会有较好性能,但 VARCHAR、DATE 或 DECIMAL上的索引则效率不高。可能需要重新设计,以尽可能高的效率访问数据表。
因此,建立索引始终是一个微妙的决策,因为太多的索引和太少的索引都一样糟糕,并且要建立索引列的数据类型,对最终结果有很大的影响。
不良做法第 8 号:糟糕的命名约定
这是程序员在面对已有数据库时总是遇到的难题:通过表和列的名称来了解其中存储了哪些信息,因为可能没有文档,没有其他方法。
表名必须描述它保存的实体,每个列名必须描述它代表什么信息。这种命名很简单,当表必须相互关联时,它就会变得复杂。名称开始变得混乱,更糟糕的是,如果存在令人困惑的命名约定和不合逻辑的规范(例如“列名称必须是 8 个字符或更少”)。最终的结果是数据库变得不可读。
因此,如果希望数据库能够持续存在并随其支持的应用程序一起发展,则始终需要命名约定,以下是我们总结的,如何建立简洁、简单且可读的命名约定的一些准则:
-
对表或列名称大小没有限制。拥有一个描述性的名称比没有人记住或理解的首字母缩略词要好。
-
相同的名称具有相同的含义。避免具有相同名称但类型或含义不同的字段;这早早晚晚会令人困惑。
-
除非必要,名字不要画蛇添足。例如,在表“Item”中,不要写成“ItemName”、“PriceOfItem”或类似这样名字的列;“Name”和“Price”就足够了。
-
请注意与 DBE 的保留字。如果一列被称为“Index”(这是 SQL 保留字),请更换使用不同的字段,例如“IndexNumber”。
-
如果坚持简单的主键规则(自动生成单个整数),请在每个表中将其命名为“Id”。
-
如果连接到另一个表,请将必要的外键定义为一个整数,命名为“Id”,后跟连接表的名称(例如,IdItem)。
-
如果有命名约束,请使用描述约束的前缀(例如“PK”或“FK”),后跟所涉及的一个或多个表的名称。少量使用下划线(“_”)有助于使内容更具可读性。
-
要给索引命名,请使用前缀“IDX”,后跟表名称和索引的列。另外,如果索引是唯一的,请使用“UNIQUE”作为前缀或后缀,并在必要时使用下划线。
本文为 @ 场长 创作并授权21CTO发布,未经许可,请勿转载。
内容授权事宜请您联系 info@21cto.com或关注 21CTO 公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。