分享到

简介

数据库绝非孤立存在。用户、应用程序、脚本,甚至其他数据库都像生物消耗和分配环境能量以及彼此能量一样,将信息馈入数据库并从中提取信息。没有哪个数据库的规模或复杂性可以与地球的全球生态系统相媲美,但设计和支持信息系统仍然与照料较小的生态系统(如花园、温室或玻璃容器)有许多相似之处。

经典的生态划分也可以应用于数据库在信息系统中的角色:动物、植物还是矿物?要确定哪种模式适合给定的数据模型,需要尽可能地理解它所处的环境。

Animal, vegetable, and mineral modes

“动物”似乎描述了一种积极的组织原则,它嵌入(或不客气地说,纠缠)在运营流程和工作流程中,经过调整、编程——总而言之,是专用的。“动物”方法在围绕单个数据库作为信息流收集器和单一事实来源显式构建的紧密聚焦的系统或子系统中表现非常出色。如果失去这种焦点,“动物”数据库可能会变成更像一只大熊猫:行动迟缓、维护成本高昂,并且是后勤和官僚机构的噩梦。

更“植物性”的数据库物种组织其获取的数据,仅此而已,在不采取积极行动的情况下约束和改进信息。这些数据库牺牲了集中化和对工作流程的积极控制,以换取适应性,收集和组织信息,而不在更刚性的数据库结构中编码行为和使用假设。在数据库不是唯一的信息处理场所或更大的团队和沟通结构交互的系统中,处理不太程序化的数据库(被视为一个而非主要的组织原则)可能更容易。

还有其他“矿物”数据库设计甚至放弃了对信息的最低限度的权威,仅提供具有最基本结构的存储,例如五千年前的泥板,苏美人在其上印刻了从分类账到投诉的所有内容。确实,有时情况只需要一个 符合 ACID 标准 的电子表格,但更仔细地查看系统是完全有必要的。也可能现有的“矿物”数据库的实现未能考虑到或笨拙地近似于更复杂的数据模型,或者部分或全部数据模型本身不适合关系表示。

数据库,复数

每个与数据库交互的程序或系统(不包括设计人员、用户或开发人员)也具有生态角色,消耗和生成信息,组合信息、分离信息,为好或坏地添加或消除细微差别。许多这些交互系统都有自己的数据模型,目标系统的数据模型的全部或部分现在构成了这些数据模型的组件(有时是通过谚语中的“幽暗不明的镜子”,任何曾经诅咒意外的 VARCHAR(20) 的人都可以证明)。

这些连接意味着数据库设计必须经常至少容纳其他数据模型(外部于自身)的某些假设,即使不是结构元素。信息被分割:一个数据库中的用户和预订,另一个数据库中的酒店空房情况,航空公司提供的航班预订以及在用户和预订端重复的航班预订。模式变得纠缠不清,并且一个数据库中的更改会对其他数据库产生影响。

管理更多事物以及它们之间更多的交互总是更困难的,尤其是在多个存储中拆分数据模型会产生深远的影响。使用模式更安全地完成对完全关系模型的子部分的封装和寻址,所有主要的 RDBMS MySQL 除外 都支持模式。但事情发生了。有些信息更适合非关系结构。有些信息已经分布在属于其他系统的数据库中,或者面向服务的架构(宏观或微观)的采用使得分裂不可避免。更严格的弹性要求需要联网的冗余存储。数据模型现在比以往任何时候都更需要考虑分布在多个交互式数据存储中。

拆分数据模型最重要的损失是引用完整性。在单个数据库中,服务器可以阻止违反外键约束的操作,例如插入或更新具有不存在的父 ID 的记录,或者 删除 其他记录所依赖的记录。将数据模型的一部分移动到另一个存储中,现在维护正确性是您(和您的团队)的问题。

专用解决方案

与任何事物一样,引用完整性是一种可协商的约束,如果能获得足够的回报,牺牲它是可以接受的。有时,如果数据模型在图论意义上足够简单,实体少,实体之间的连接很少或主要是分层连接,或者两者兼而有之,那么甚至不是一个需要提出的问题。性能和可伸缩性要求也可能为引入关系模型的替代方案提供理由,其中数据模型的某些部分表示比 RDBMS 更容易容纳的更高容量和更快变化中的真实信息。

00 年代后半期见证了这些替代方案的寒武纪爆发。突然出现了“NoSQL”数据库,用于存储文档、图形、键值对。列式存储通过将表横向旋转并建模扁平的、非规范化的数据,实现了令人震惊的性能。新来者拥抱跨网络服务器的横向扩展,抛弃了 ACID 剧本,转而支持 BASE(“基本可用、软状态、最终一致性”),并为 SQL 陌生的概念开发了 API 和特定领域的语言。不仅如此,围绕数据存储的对话重塑模糊了数据库作为概念的界限。像 Kafka 这样的流处理器是数据库吗?像 ElasticSearch 这样的搜索引擎呢?每个都从根本上促进了信息的存储和检索;讨论任何一个都需要调用许多数据库的技术语言。更根本的是,每个都是解决特定类型数据建模问题的方案。

如果您需要存储和处理...请考虑...
连接较少的层次结构、原始结构化文档或至少具有一些共同字段的对象文档数据库(Couchbase、MongoDB)
大量“扁平”数据,例如仪器读数或结构化分析面向列的数据库(Cassandra、HBase)、时序数据库(TimescaleDB、InfluxDB、Druid)
通过键标识且仅通过该键查询的记录键值存储(Redis、LevelDB)、缓存(memcached)
记录之间具有点对点导航的复杂关系图形数据库(OrientDB、Neo4j、TerminusDB)
按接收顺序排列的瞬态数据馈送流处理器和队列(Kafka、RabbitMQ、ZeroMQ)
文件。大量文件云文件存储(Google Cloud Storage、Amazon S3 和 Athena)
非结构化文档,或具有高度可变模式的结构化文档搜索引擎(ElasticSearch、Solr)、内容存储库(Jackrabbit)
行星级规模的关系数据NewSQL 高度分布式关系数据库(VoltDB、Spanner)
以上至少几种多模型数据库(FaunaDB、ArangoDB)

请注意,以上只是示例,并非认可!Kristof Kovacs 还维护了一个更详细的摘要,其中包含许多 NoSQL 选项,从流行的到晦涩难懂的。

默认

如果您不需要存储至少千兆字节的对其他关系数据模型的异常,您甚至可能不需要放弃 ACID 和引用完整性!关系数据库通常在全文搜索和存储结构化或非结构化文档方面非常强大;PostgreSQL 的 JSON 方法尤其广泛,具有可索引的二进制存储和丰富的查询工具集,使混合关系-文档策略切实可行。Postgres 和其他 RDBMS 都通过服务器组件、扩展或存储引擎支持其他模型,一些专用存储(如 TimescaleDB)构建在关系数据库之上。

因此,尽管数十个营销部门尽了最大努力,但历史悠久的半个世纪的关系型数据库仍然是首选的通用数据存储,非关系型解决方案找到了适合其优势的专用利基市场。NoSQL 数据库可以完成其关系型数据库对应物无法轻松完成或根本无法完成的各种事情,但关系型数据库在可预见的未来仍将存在。通过 服务器调优、索引和表分区,单个关系数据库可以容纳除最繁重的工作负载之外的所有工作负载。即使这还不够,仍然有复制。

复制和架构

深入介绍复制技术超出了数据建模指南的范围,但它们的使用确实会产生不可忽视的后果。复制数据库不仅仅是更大:一旦数据存储联网,它就不再是整体系统架构的单个元素。复制引入了一整套围绕延迟、网络分区、维护等的新问题。

最常见的复制形式涉及仅将数据写入单个 服务器。主服务器将更改转发到一个或多个副本服务器,这些副本服务器要么待命以在其发生故障时替换它(故障转移),要么承担响应读取查询的工作。在后一种情况下,网络延迟可能意味着更改可能不会立即可见,但由于它们仅单向流动,因此仍然保证一致性。读取和写入的分离自然而然地适用于在适当的情况下在视图中表示合并的实体,尤其是在软件系统中,适用于 命令查询责任分离,这是一种设计模式,可以帮助控制仅与检索或存储相关的复杂性。

在另一种“多主”复制模式中,数据可以写入和读取自多个服务器,这些服务器联网后,在重负载下比单个服务器更具弹性。但是,制定共识很复杂,并且实现更高级别的写入验证以保证持久性可能会很慢。这往往需要更简单的数据模型和更精细的冲突和回滚处理。

大多数 NoSQL 数据存储都设计用于集群,有些甚至到了能够在单台计算机上运行几乎是事后才想到的。特别是,NoSQL 将分片或从集群中不同节点提供表分区的想法推到了前台。分片是这些数据库实现规模的主要因素,但如果没有复制,丢失节点仍然意味着丢失数据。大多数 NoSQL 数据库都提供基本复制,通常具有自动故障转移功能。少数数据库(如 Cassandra 和 Couchbase)使用多个主节点。

CAP 定理

他的“CAP 定理”(一致性、可用性、分区容错性:三者取其二)至今仍引起共鸣,但与动物/植物/矿物的三分法一样,是一种优雅的过度简化——仅此而已。

Martin Kleppmann 在 2015 年详细描述了 CAP 的缺点,并基于 Coda Hale 早期的努力 澄清“三者取其二”方面。Brewer 本人后来宣布 Google 的 Spanner 数据库 “实际上是 CA”,这要归功于 Google 网络的庞大规模,克服了 AP/CP 二分法。

集成外部信息

信息很少仅在系统的数据库或多个数据库及其用户之间流通。大多数信息系统都是开放系统,数据从其他信息系统流入和流出。这些流动通常适合自动化,并且在达到某个不太大的量时,几乎成为强制性的;手动数据输入是最后的手段。有时,外部信息源始终在线,队列、流处理器或专用守护程序在记录到达时添加记录,但一次不会做太多事情。但是,有时实时数据可能不可用或根本不必要——每月销售额或昨天的网站分析不需要精确到秒。

批量数据摄取过程通常被称为首字母缩略词 ETL,即提取-转换-加载,即使在非正式情况下,没有发生提取或转换。典型的 ETL 过程是 cron 作业或计划任务,它从外部系统下载存档数据导出,通常是平面分隔格式,如 CSV 或 TSV。记录可能会在 ETL 任务将其写入数据库时进行转换,或者,违反首字母缩略词,之后批量转换。当涉及到与现有数据的连接时,批量转换尤其有用,因为数据库可以优化一次数千行的连接,而不是数千次单行连接。

Integrating external information

用于数据导入的第一方工具各不相同。专有的 RDBMS 通常包括专用的 ETL 管理程序,例如 SQL Server Integration Services 或 Oracle Data Integrator,而主要的开源和 NoSQL 选项通常止步于基本文件加载,应用程序如 mysqlimportmongoimport,或服务器端 COPY 命令(在 PostgreSQL 和 Cassandra 中)(Postgres 还在 psql 客户端中提供客户端 \copy 指令)。

但是,第三方 ETL 自动化正在成为一个可行的商业利基市场,尤其是在越来越多的数据库托管在云端的情况下。如果您有大量不同的传入流或严格的法规遵从性约束,则可能值得研究这些服务。它们并没有做任何您无法使用现有工具完成的事情——问题是您是否有时间自己实施和维护足够强大的 ETL 流程。

联邦:统一信息来源

ETL 不是唯一的选择。2003 年,SQL 标准引入了一个名为 SQL/MED 的扩展,即外部数据管理。文件、其他数据库、其他关系型或非关系型 DBMS、REST 端点、目录服务——所有这些以及更多都涉及看起来很像列和行的数据集,至少从正确的角度来看是这样。任何看起来足够像列和行的东西,如果不能完全管理,也可以通过 SQL 进行查询。数据库向用户和其他外部系统呈现单一界面,同时将请求和更改路由到适当的目标。

在 IBM 的 DB2 首次实施后,其他数据库需要花费数年时间才能赶上 SQL/MED。目前,Oracle 支持对平面文件进行读/写访问,作为“外部表”,而 SQL Server 可以连接到“链接服务器”,只要它们符合 Microsoft 的 OLEDB API。

真正有趣的事情正在开源 RDBMS 中发生。PostgreSQL 在 9.1 版本中引入了 外部数据包装器,并继续扩展其功能,而 MariaDB 的 CONNECT 存储引擎 可以包装大量数据源。此外,Postgres 和 MariaDB 的实现都是可扩展的:如果您的外部数据采用现有包装器无法处理的格式,您可以编写自己的包装器。Postgres 社区甚至开发了一个名为 Multicorn 的 Python 框架,以简化原本基于 C 的外部数据包装器开发过程。

“联邦”架构的思想源于区域政府和中央(联邦)政府共存的双重政府形式,并且像其他系统设计技术一样,其目的是管理复杂性。各个子系统的用户在这些子系统中工作和使用这些子系统;那些只关心整体运作的人与整体互动。从生态角色的角度来看,这非常类似于数据库操作的“动物”模式。联邦数据库是其所处系统的中心。它将信息流吸引到自身并通过自身,建立连接,编码对附属模式的期望。但在这种野兽可以蓬勃发展的信息生态系统中,SQL/MED 是控制不同数据源的强大工具。

关于作者
Dian Fay

Dian Fay

Dian 并没有完全计划从大学辍学来专门研究 SQL 和后端开发,但事情就是这样发生的。十五年后,她设计的数据库支持从工业物流和可追溯系统到百万级用户社交媒体游戏的一切。她是 MassiveJS 的当前维护者,MassiveJS 是一个用于 Node.js 的开源数据映射器,专注于充分利用 PostgreSQL。