Rey*_*rPM 10 mysql normalization database-design relational-theory denormalization
我正在与我工作的公司的开发人员进行永久讨论,因为他们说最好摆脱关系数据库中的关系强制(通过 FOREIGN KEY 约束定义)以加快大型查询并获得更好的结果表现。
考虑的平台是MySQL 5.x,没有设置FOREIGN KEY,甚至缺少相关表的一些PRIMARY KEY约束,至少对我来说是不合理的。也许他们是对的,我是错的,但我没有足够的论据来讨论这种情况。
三年来,这一直是首选方法。我是这家公司的新人(只有一个月),但是,随着产品“有效”,我对增强数据库犹豫不决;尽管如此,我注意到的第一件事是加载一个页面需要 1 分钟(是的,60 秒!)。
当前状况背后的说法之一是“非规范化”数据库比规范化数据库更快,但我不相信这是真的。
大多数相关查询都包括 JOIN 操作,这使得它们在处理大量数据(数据库包含数百万行)时运行非常非常缓慢。
通常,“CRUD”操作的处理是在应用程序代码级别实现的;例如,为了删除一些数据,让我们说TableA:
TableA和TableB,你能帮我详细阐述一个好的、准确的和可靠的答案来丰富辩论吗?
注意:以前可能有人问过(并回答过)类似的问题,但我无法通过 Google 找到任何内容。
MDC*_*CCL 13
如果,如您的帖子所述,目的是创建一个关系数据库(为简洁起见是 RDB),因此,它的功能是这样的,那么简短的回答是:
主要目标应该是按原样管理相关数据:一项非常有价值的组织资产,实现所述目标的可靠方式是采用有可靠理论支持的技术手段。
因此,作为数据库专业人员,您可以利用EF Codd 博士提供的最先进和优雅的关系模型机制来强制执行业务规则,并避免在以下情况下最终会出现的(技术和组织)问题它们没有被利用。
在这方面,我将分享 (a) 我对约束的总体看法,以及 (b) 对数据库状况和相关工作环境的一些考虑,如下所示。
RDB 必须高精度地反映感兴趣的业务上下文的特征,这肯定需要由遵循最佳实践的建模者或设计者领导的深入概念级分析,并在业务专家的不可或缺的帮助下进行计数。该分析必须产生正确的识别和制定适用的业务规则。
因此,如果这样的建模者已经确定相关数据之间存在相互关系,他或她必须配置相应的逻辑级限制,以便数据库管理系统 (DBMS) 可以保证数据与确切的特征保持一致,并且任何时候都在上面提到的分析中确定的规则。
关于所讨论的数据库,人们可以推断出相关的相互关系已经确定,因为您提到有一种程序性的(并且很容易规避)尝试从 DBMS 设施外部通过应用程序代码(其中是一种关系前的方法)在任何情况下都必须“接触”数据库以尝试验证所述相互关系的完整性。
然而,如您所知,这不是保护参照完整性的最佳技术,因为关系科学为此目的规定了一种非常强大的工具,即外键 (FK) 约束。这些约束很容易创建(通过高级声明方法),因为它们是单个句子,避免诉诸不必要和容易出错的临时程序。注意到 FK 约束的执行速度已经被专业程序员高度优化是非常有用的(并且主要平台供应商已经为此工作了几十年)。
此外,由于 RDB 必须是一个独立的(自我保护、自我描述等)软件组件,能够被多个应用程序(桌面、自动、网络、移动、它们的组合)访问,它不应该是与任何这些应用程序的代码“耦合”。
同样,作为重要的组织资源的数据自然会比应用程序、应用程序程序员、应用程序开发平台和编程范式更长寿。
当——从概念上讲——某种特定事物在业务环境中被认为具有重要性时,数据库建模者必须 (1) 确定其相关特征——即其属性——,将所述事物确认为实体实例原型——即,一个实体类型——和 (2) 通过一个表的方式来表示它,该表由逻辑设计中的一个或多个列集成。
然后,就像在现实世界的业务中区分给定实体类型的每个单独实例至关重要一样,表中包含的每个对应行也必须唯一区分。如果一个表没有声明任何KEY,它最终会保留重复项,如果有两行或更多行保留完全相同的值,那么它们都带有相同的含义,它们都代表相同的事实。
在这一点上,由于多种原因,应该丢弃重复的行。从理论的角度来看,设计者必须确保每一行始终是唯一的,目的是让表在 SQL 数据子语言允许的情况下工作(对数据操作操作有重要影响)。此外,从信息的角度来看,如果多行代表同一事实,记录它们不仅是多余的,而且是有害的,如下例所示:
通过这种方式:
如您所知,这种现象甚至会产生法律影响,这种情况肯定非常重要。
此外,处理此类矛盾(可能通过某种“更新同步”)所必须花费的时间和精力最好用于为您的组织实际产生价值的任务。因此,在设计上应该避免保留矛盾的行,以保持数据库的一致性。
这就是为什么 PRIMARY KEY (PK) 的标识和相应约束的声明应始终由数据库设计人员执行的原因。但还必须提到的是,一张表可能有不止一列或多列的组合,这些列包含唯一标识每一行的值;因此,除了设置 PK 约束(出于实际原因,理想情况下建立为 PRIMARY),设计者还必须在应用时声明一个或多个 ALTERNATE KEY(通常通过一个或多个 UNIQUE 加上 NOT NULL 约束定义)(即很常见)。
PK 的另一个优点是,当“迁移”到其他表以参与单个或复合 FK 时,它们可以帮助强制执行数据之间存在的关系/关联的基数比。所有这些,是的,通过简单有效的声明性设置,由 DBMS 始终确保。
让我们不要忘记(当前)CHECK 约束的相关性,即声明性地限制行的有效列值集(这可能看起来很简单,但实际上是关系 DBMS 的一个基本特征),也有助于使确信业务环境的规则总是准确地反映出来。
当您用 MySQL 标记标记您的问题时,从8.0.16版开始(另请参阅此 MySQL 服务器团队博客文章)终于有了这样的平台!强制执行这种类型的约束。在这方面,必须提到的是,在其所有以前的版本中,该 DBMS 确实允许声明 CHECK 限制,但忽略了其强制执行!, 可以理解的是,自 2004 年以来,这种情况被报告为错误。
所以,如果使用旧版本,你就必须通过其他手段,例如,为了照顾这个因素的ACID事务,触发器或数据库管理系统本身的其他方法(见本答案由@ypercube ?? 有关此主题的信息),所以数据继续保持一致。
无论出于何种原因,包括 MySQL 在内的不同 SQL DBMS 都极不支持(如果有的话)的一个方面是以声明性方式启用多行和多表约束——显然超出了 PK 和 FK。
就其本身而言,SQL 标准已经包含了多年以来的断言。我不知道您的业务环境的哪些规则会从这种逻辑级验证方法中受益,但是,作为一名数据库设计人员,我认为在需要时使用一个或多个断言来约束数据会非常方便,尽管我不得不提到从 DBMS 开发人员的角度来看,这种最重要的工具很难在物理抽象级别实现。
自 2016 年以来,Oracle 供应商和/或开发人员似乎正在评估ASSERTION 支持,这将使 DBMS 更加符合关系,因此更加强大和具有竞争力。我猜想,如果 (i) 他们的消费者继续推动并且 (ii) Oracle 在实施方面取得成功,那么 (iii) 其他 DBMS 供应商/社区也将不得不启用它们,并且它们的使用将开始传播。当然,这将是数据管理领域的一个巨大进步,而且作为 Codd 博士设想的最独特的工具之一,我个人希望我们很快就会看到这一点。
如上所述,RDB 最重要的方面之一是它自己保证其保留的数据的一致性,并且仅当 RDB 符合建模者声明的完整性约束时才满足所述一致性。
在这方面,必须具有受完整性保护的基表(在 DDL 结构中建立的表),以便能够创建可信赖的派生表(例如,从多个表中检索列的 SELECT 语句或视图),因为必须根据基表生成派生表。
很明显,人们将信息用作组织(和普通)决策过程中的主要工具。然后,如果数据库提供的信息不连贯且不准确,则基于此类信息的决策将不合理(至少可以这么说)。这就是 RDB 必须精心设计和实施的原因:它应该被构建成一种可靠的资源,可以帮助其用户做出有充分根据的决策。
唉,“一个'非规范化'的数据库比一个规范化的数据库更快”是一个广泛传播的误解,尽管它也是一个可以在逻辑、物理和实用上反驳的“论点”。
首先,非规范化必然意味着基表先前已被规范化(通过在数据库抽象的逻辑级别实现的正式的、基于科学的程序)。
因此,假设该表实际上已正确规范化,则对其进行“非规范化”(与该词的正式含义相反,涉及将属于广告中其他表并且也是其一部分的列附加到该表中)hoc方式)可能有助于,例如,加快(在物理级别)仅一个或几个特定 SELECT 语句的处理,而这种操作过程可能同时会破坏许多其他相关数据的执行操作操作(例如,多个 INSERT、UPDATE、DELETE 和 SELECT 语句,或包含在单个或多个 ACID TRANSACTIONS 中的组合)。
此外,非规范化(无论是正式的还是非正式的)会引入更新/修改异常,从而恶化数据库的一致性,这个问题“可能”通过复杂、昂贵且容易出错的程序来处理,而当所有这些都可以避免时一开始。
支持规范化和“非规范化”表的物理级脚手架
旨在在现实世界中使用的逻辑(抽象)布局(SQL-DDL 设计)显然包含必须考虑的物理(具体)影响。
以这种方式,“非规范化”表必然会“更宽”(包含额外的列),这意味着它的行必然会更重(需要更多和更大的物理级组件),因此这意味着底层计算过程(例如,那些与硬盘驱动器或内存有关的)很容易变慢。
相比之下,当然“更窄”(具有更少列)的规范化表将是“更轻”元素(由越来越小的物理组件提供),“行为更快”,这将加速与相关的一系列操作例如,数据写入和读取。
既然如此,那么 (a) 正式和谨慎地规范化相关表,保持它们原样,然后 (b) 利用任何可以优化数据检索和修改速度的物理级资源,这是非常方便的,例如,实现谨慎而有效的索引策略,支持适当的软件和硬件服务器配置,升级网络带宽能力等。
您问题的以下段落与数据检索操作的速度有关:
[A] 产品“有效”,对增强数据库有犹豫;尽管如此,我注意到的第一件事是加载一个页面需要 1 分钟(是的,60 秒!)。
如果加载某个页面需要这么长时间,很明显系统的用户没有得到适当的服务;因此,即使它“有效”,它的功能似乎也根本不是最佳状态,这表明您使整个计算机化信息系统(数据库和应用程序)更高效的意图得到了很好的维持,并表现出非常有建设性的态度.
那么,即使科学肯定支持你,因此你应该保持坚定的姿态,我建议以外交方式处理这种情况,因为在一天结束时,你的雇主、同事和你自己正在联合努力,以求使整体组织更成功。因此,这是您应该强调的一个论点,即虽然他们在其他方面做得很好,但改进一般和特定的数据管理实践可以极大地帮助产生更多的组织和个人成长。
大多数相关查询都包括 JOIN 操作,这使得它们在处理大量数据(数据库包含数百万行)时运行非常非常缓慢。
值得注意的是,JOIN 运算符是与数据的关系操作相关的重要且强大的元素。然后,尽管更强大的平台以相对更快的执行速度为其提供服务,但您描述的情况很可能是设计效率低下的症状(在抽象的概念、逻辑和物理级别)。所以,我的第一眼估计是:
此外,是的,正如@TommCatt在他的回答中提到的那样,有时查询的(逻辑)重写会修改其(物理)执行计划,加速数据读取/写入,这是一个应该明确考虑的因素。
你的开发人员的基本前提是绝对错误的。外键会轻微影响系统 DML 的性能。它们根本不在查询中使用,因此对它们的性能没有影响。因此,您的开发人员不知道他们在谈论什么,并且是您最不应该考虑向其提供建议的人。
外键在维护数据完整性方面发挥着关键作用。这比通过删除它们获得的任何微小的性能改进(即使是真的)重要得多。
在任何情况下都不要从 OLTP 数据库中删除 FK。
此外,非规范化有时会加速某些查询。正如他们所说,这取决于。尽管如此,即使速度有所提高,通常也不值得为维护数据完整性付出额外的努力。
当简单的调整不能比非规范化获得更多的速度提升时,这是非常罕见的。这是一个优秀的 DBA 可以(最终)获得报酬的地方。您还可以调整您的查询。我曾经接受过一个查询,该查询在不少于 30 分钟内返回了答案,并在 8 秒内使其工作。没有更改数据库,只需重写查询。当然,这是我个人最好的记录,所以你的里程可能会有所不同,但非规范化应该是你尝试的最后一件事。
您可能还希望避免开发人员编写更复杂的查询。询问他们想要什么数据以及他们想要的格式。然后提供视图以将其提供给他们。复杂的查询将是视图。然后开发人员只需编写:
select <something> from <SomeView> where <whatever>;
Run Code Online (Sandbox Code Playgroud)
我还假设您的数据库设计良好。一个糟糕的数据库设计,甚至是它的一小部分,都会真正减慢速度。我经常使用非常大的表(每个表有数十亿条记录),其中的查询将它们左右连接在一起,并在几分之一秒内得到预期(并得到)答案。表的大小并不能决定查询的速度。
当有人说“因为产品'有效',所以在增强数据库方面犹豫不决时,我真的很害怕。” 如果这种“犹豫”更像是“不在我的监视范围内,伙计!” 那么你甚至可能想要开始更新你的简历。这样的环境不会带来任何好处,即使您可能已经游说数小时以做出可以防止失败的更改,但您仍会为未来的每一次失败承担责任。您会一遍又一遍地听到“现在不是进行更改的好时机”。对。祝你好运。