Eri*_*art 5 nosql document-oriented orm relational-theory denormalization
编辑: 这个问题是关于如何处理在整个系统设计中出现的许多问题,这使得系统的某些部分偏离了通用标准。例如,使用自己的程序代码管理业务模型中的所有内容,甚至关系完整性。这给数据库和持久层带来了一种糟糕设计的味道,将其用作“将某些内容转入并以某种方式再次取出”的地方,而不是结构化存储。我问了这个问题,因为在我看来,NoSQL 文档存储就像一个选项,可以将已经无模式(或非常松散的模式)数据库移动到默认情况下没有模式的数据库。此外,我必须指出,尽管这里描述了一些缺陷,但整个系统根本不是一个坏系统。此外,一些问题,例如版本控制,已经有了解决方案或已经实施。
想想你看到的一个软件系统,基于经典的关系数据库(SQL Server、Oracle)、NHibernate作为对象关系映射器(ORM)、顶部的业务逻辑模型层和大量模块(几百个) ,主要是基于 .NET 的服务和一些 Web 服务(带有客户端,每个系统/客户最多约 100 个,公司网络,非公共)。操作方式主要是OLTP,写/CUD访问是工作负载的重要组成部分。生产数据库通常大约为 10GB,但大小总是远低于 100GB(因此没有“大数据”)。它确实工作得很好,但对我来说,数据库和 ORM 实现有几种反模式(对于关系数据库)的味道。也许这些实现对于另一种数据库会更好——面向文档(“NoSQL”)或内存数据库。
省略了许多关系数据库和支持 ORM 的功能:表被强烈反规范化,外键关系丢失或不可能,例如由于元数据表引用不同的主表,列如IdInTable INT, OwnerTable INT
. NHibernate 几乎没有映射对象关系(并且通常存在不适合它的表结构的问题)。相反,这些是在业务逻辑中实现的(有时会导致孤立的子对象或低效的数据库访问,见下文)。
基础之下的非规范化:增加非 1st NF 数据的使用:带有 XML、逗号分隔列表或复合数值列的 nclob/nvarchar(max) 列(例如,任务类型 123 的 123、10123、40123,但模块配置不同由 0,1,4 * 10000 标识)。前两个包含数据库相关、逻辑“外键”和数据模型相关值,例如<UserType>AdminUser</UserType>
(要检查LIKE '%...%'
)。这主要是由于许多快速发布、短暂存在和自定义的值不应该进入主模式,或者更容易通过 XML 值实现。
非 2nd NF 数据,包括由触发器、后续存储过程或应用程序复制到其他表中的表内容。例如,将表列值复制到“垂直”元数据表,这再次复制到元数据的“水平”或“旋转”表示(每个元数据类型为一列),因为某些应用程序只能使用元数据或水平元数据. 经常要求使用“垃圾箱结构”(将从各种来源收集的数据转储到一个 nclob/nvarchar(max)“垃圾箱”列中,并让应用程序搜索它,而不是许多不同的来源)。
业务逻辑模型和应用程序中的“单一对象疾病”: 单个对象的迭代和立即加载/保存:业务层主要使用 Load/Save() 方法来处理单个对象和少量基于批量/集合的操作。一个常见的工作是通过 SQL 或者它的 NHibernate 表示来获取对象 ID,然后遍历所有检索到的 Id 并以foreach (oneId in Ids) { myObjects.Add( BizModel.GetMyObjectById(oneId) ); }
. 这包括所有元数据、依赖对象集合等,这是典型的 SELECT N+1 情况。此外,大多数 NHibernate 的缓存、持久性无知和组合操作都被强制禁用:加载一个对象显式调用SELECT FROM MyObject WHERE Id=:id
以防止使用缓存或延迟执行,但从当前 DB 行获取一个新对象。MyObject.Save()
实施以强制立即插入/更新:session.Save(...)
其次是立即.Flush()
。整个过程使用 NHibernate 微会话:加载的对象会立即从会话上下文中取出并保存在新会话中(防止 DB 中未保存对象的那些“奇怪”的、不需要的更改)。通过 NHibernate 的持久性无知和对象关系似乎是不可取的,以保持对每个对象的状态的控制。NHibernate 实际上被认为是一种映射器(一行到一个对象),而不是用于关系数据库访问的复杂工具。还有关于使用“快速”微 ORM 代替 NHibernate 的争论,这将使 SELECT N+1 查询闪电般快速地物化为对象,但当然对 N+1 本身没有任何作用。
一个重要的要求是让每件事都与一切一起工作,因为每次更改都发布所有模块太多了:新模块必须与旧数据库版本一起使用,其中某些列和表不会退出,而旧模块必须仍然使用新的数据库版本,添加列等。这会导致新列具有默认值(如果不可为空),并且旧表/列被废弃很长时间,仍然在数据模型中,因为删除可能会使旧模块崩溃。另一个后果是不愿意添加新的表/列,一旦发布就很难摆脱。相反,首选 XML(在文本列中)和类似的、非规范化的内容或全局元数据表中的属性值。
许多模块只接收单个对象的任务,这在可能的、基于集合的方法中是没有问题的,因为如果需要,集合/批量数据访问方法也可以处理单个对象/行。另一方面,有 web 服务器、维护和后台服务,它们一次处理多个对象,需要业务逻辑,并且在当前的单对象方式下运行效率非常低(使用原生 SQL 的 web 服务,或者,新的,一个基于 Lucene 的搜索引擎搜索所需对象的 ID,但要一一检索完整的模型对象)。
想象一下,你已经试图改变这一点。一开始,您不了解 NHibernate 及其工作原理,但后来您想出了如何使数据访问适应其真正能力的想法,并避免不必要的数据库操作:在 NHibernate 中映射关系,保持会话和事务打开多个对象操作,设置/批量操作,按照您多年前学习的方式规范化数据库,添加外键、视图,也许是物化视图。但是你一直被拒绝,理由是:“没有人会为此买单”,“数据库可以处理它,无论应用程序有多‘糟糕’”,以及简单的“它可以工作”. 磁盘空间、内存、CPU 能力和网络资源都很便宜;重构数据访问会更加昂贵。可能,首选代码程序员的面向对象方法,而不是 DB 程序员的基于集合的方法(包括它对 ORM 实现的强制执行)。如果系统以目前的方式工作得足够好,那么系统可以快 10 倍甚至 100 倍又有什么关系呢?反正不管SELECT N+1,今天的数据库都能搞定!那只会是镀金!当数据库增长到 TB 时,情况可能会有所不同,但目前还不是这样。
所以,也许在“NoSQL”或“NewSQL”领域有一个解决方案。有可能以快速有效的方式从数据库中获取对象并将其存储在数据库中。即使在单个对象中有许多查询,而不是 set 方法,只要它是本地 DB,没有长距离延迟。看起来现在的系统把关系型数据库当作一个扩展的、持久的主存,而所有那些 IT 的“石器时代遗留物”,比如手动创建和维护表和索引,或者将对象映射到关系表,只需添加一个巨大的高架。
我的想法是:
“NoSQL”文档数据库是个好东西,因为:
仍然需要最低限度的自动化数据完整性,尤其是多对象事务。
内存关系数据库,或任何专注于快速访问而无需每次(写入)操作都访问慢速硬盘驱动器的数据库,将有助于提高速度,但仍然基本上依赖于硬关系模式,该模式尚未在很大程度上被省略和对利益相关者来说似乎是不受欢迎的。
任何有经验的人都可以告诉我我的假设是否正确?
欢迎来到数据库地狱!
NoSQL 通常被认为是这些类型应用程序的解决方案。但是,您的问题显然是程序员不知道他们在做什么。此外,看起来你的管理层害怕改变,或者不愿意做出你正确列出的、可能解决根本原因的艰难决定。用另一个数据库替换数据库在这里很有帮助是高度不确定的。不怪工具,怪工匠。
虽然 NoSQL 中的每个对象都可能包含整个对象图,但您仍然坚持如何以适当的完整性使所有数据保持最新。顺便说一句,这正是 3NF 旨在解决的问题,它在所有设计合理的系统中都能很好地解决。一旦您维护了冗余数据(无论是在 SQL 还是 NoSQL 中),您就会遇到各种锁定和闩锁以保持同步的问题。
NoSQL 的动态模式特性仅在模式更改非常频繁时才具有优势。从你对系统的描述来看,听起来不像是这样,因为没有人敢碰代码。此外,关系数据库中的模式更改并不难。NoSQL 支持的动态模式的优势在很大程度上是一种解决方案,它寻找的问题对于知道自己在做什么的 DBA 来说是不存在的。
即使您可以获得 NoSQL 的一些理论上的好处,您仍然必须考虑如何从您所在的位置迁移,而不会遇到您当前面临的所有相同争论。在不接受彻底变革的环境中,比较这两种方法的成本可能会令人望而却步。
我完全理解你为什么在这里努力寻找解决方案。但是,IT 领域有很多出色的工作。生命太短暂,无法处理这种类型的系统和组织。除非你需要耐心和忍受痛苦的教训,否则就继续前进。
归档时间: |
|
查看次数: |
1377 次 |
最近记录: |