数据库操作的经济效益

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
简介: 转为使用文档数据库并实施恰当的数据建模技术,就有机会提高效率、节省资金。

面对不断上升的成本以及不明朗的经济形势,许多组织都在探索各种方式,以期取得事半功倍的效果。数据库也不例外。所幸,转为使用文档数据库并实施恰当的数据建模技术,就有机会提高效率、节省资金。


文档数据库从两个方面为公司节省资金:

  • 1. 以对象为中心的跨语言 SDK 和架构灵活性,让开发人员能够加速创建和迭代生产代码,从而降低开发成本。
  • 2. 减少实现规定事务吞吐量所必备的硬件,能够大幅降低运营成本。

开发人员效率

所有现代开发都用到了对象概念。对象定义了一系列相关值,以及如何读取、修改值及从值中推导结果的各种方法。顾客、发票和火车时间表都体现出对象概念。与所有程序变量一样,对象也是临时的。因此,必须将它们保留到磁盘存储,将其变为持久化对象。


我们不再采用 Windows 桌面开发人员在 20 世纪 90 年代的的做法,不会再手动将对象序列化成本机文件。目前,数据并不会存储在执行应用程序的电脑上,而是存储在由多个应用程序或多个应用程序实例可以访问的一个集中位置。共用访问位置之后,我们既需要通过网络高效地读写数据;也需要实施机制来确保对该数据的并发更改不会导致一个流程覆盖另一个流程的更改。


关系数据库推出的时间早于已经广泛使用和实施的面向对象的编程。在关系数据库中,数据结构是内含值的多张数学表。与数据的交互需要通过专门语言 SQL,而该语言经过过去 40 年的演变,能够与存储的数据进行所有类型的交互:筛选及重新调整自身、将自身从已去重的相关扁平化模型转变为向应用程序呈现的表格化、重叠、联接结果。然后再大费周章地将数据从这么多行的冗余值再转换为程序需要的对象。


这个环节需要开发人员投入大量工时、技能和专业知识。开发人员必须理清表格之间的关系。他们还需要了解如何检索不同的信息集合,再利用这些数据行来重建数据对象。人们假定了开发人员在入行前就已经学了相关技能,只需要在工作中调用技能就行。这个假定毫无根据。即便开发人员接受过正规的 SQL培训,他们也不大可能懂得如何高效写入有用示例。


保留对象的概念催生了文档数据库。有了文档数据库后,只需用非常少的代码或转换就能将强类型对象保留到数据库;只需用范例对象来筛选、重新调整及聚合结果,不必费劲使用名为 SQL 的蹩脚英文来表达。


假设我们想要为拥有一系列重复属性的客户存储客户对象,例如,存储地址。此时,地址是不会在客户之间分享的弱实体。如果使用了 C# 中的代码/类似 Java 的伪代码:

class Address : Object {
   Integer number;
   String street, town, type;
   Address(number, street, town, type) {
       this.number = number
       this.street = street
       this.town = town,
       this.type = type
   }
   //Getters and setters or properties as required
}
class Customer :  Object {
   GUID customerId;
   String name, email
   Array < Address > addresses;
   Customer(id, name, email) {
       this.name = name;
       this.email = email;
       this.customerId = id
       this.addresses = new Array < Address > ()
   }
   //Getters and setters or properties as required
}
Customer newCustomer = new Customer(new GUID(),
   "Sally Smith", "sallyport@piratesrule.com")
Address home = new Address(62, 'Swallows Lane', 'Freeport', 'home')
newCustomer.addresses.push(home)

要将这个客户对象存储在关系数据库管理系统 (RDBMS) 后再在规定位置检索所有客户,我们需要下列代码或类似内容:

//Connect
RDBMSClient rdbms = new RDBMSClient(CONNECTION_STRING)
rdbms.setAutoCommit(false);
// Add a customer
insertAddressSQL = "INSERT INTO Address (number,street,town,type,customerId) values(?,?,?,?,?)"
preparedSQL = rdbms.prepareStatement(insertAddressSQL)
for (Address address of newCustomer.addresses) {
   preparedSQL.setInt(1, address.number)
   preparedSQL.setString(2, address.street)
   preparedSQL.setString(3, address.town)
   preparedSQL.setString(4, address.type)
   preparedSQL.setObject(5, customer.customerId)
   preparedStatement.executeUpdate()
}
insertCustomerSQL = "INSERT INTO Customer (name,email,customerId) values(?,?,?)"
preparedSQL = rdbms.prepareStatement(insertCustomerSQL)
preparedSQL.setString(1, customer.name)
preparedSQL.setString(2, customer.email)
preparedSQL.setObject(3, customer.customerId)
preparedStatement.executeUpdate()
rdbms.commit()
//Find all the customers with an address in freeport
freeportQuery = "SELECT ct.*, ads.* FROM address ad
INNER JOIN address ads ON ad.customerId=ads.customerId AND ad.town=?
INNER JOIN customer ct ON ct.customerId = ad.customerId"
preparedSQL = rdbms.prepareStatement(freeportQuery)
preparedSQL.setString(1, 'Freeport')
ResultSet rs = preparedSQL.executeQuery()
String CustomerId = ""
Customer customer; 
//Convert rows back to objects
while (rs.next()) {
   //New CustomerID value
   if rs.getObject('CustomerId').toString != Customerid) {
       if (customerId != "") { print(customer.email) }
       customer = new Customer(rs.getString("ct.name"),   
                               rs.getString('ct.email'), 
                               rd.getObject('CustomerId')
  }
   customer.addresses.push(new Address(rs.getInteger('ads.number'), 
                           rs.getString("ads.street"),
                           rs.getString('ads.town'),         
                           rs.getString("ads.type")))
}
if (customerId != "") { print(customer.email) }

这个代码冗长且会随着对象所在字段深度或数量的增加而愈发复杂,而添加新字段则需要执行大量相关更改。


相比之下,有了文档数据库后,可供使用的代码如下所示,向对象添加新字段或深度时也不必更改数据库交互:

//Connect
mongodb = new MongoClient(CONNECTION_STRING)
customers = mongodb.getDatabase("shop").getCollection("customers",Customer.class)
//Add Sally with her addresses
customers.insertOne(newCustomer)
//Find all the customers with an address in freeport
FreeportCustomer = new Customer()
FreeportCustomer.set("addresses.town") = "Freeport"
FindIterable < Customer > freeportCustomers = customers.find(freeportCustomer)
for (Customer customer : freeportCustomers) {
   print(customer.email) //These have the addresses populated too
}

开发人员遇到编程模型(对象)和存储模型(行)之间断开连接的情况时,也能快速创建出同事和未来的自己看不到的抽象层。能够自动在对象和表格之间来回转换的代码称为对象关系映射 (ORM)。遗憾的是,ORM 往往使用特定语言,将开发团队与该语言绑定,使得将其他工具和技术用于该数据的难度增大。


要执行更复杂操作时,即便使用了 ORM,也避免不了 SQL 的负担。此外,由于基础数据库不会识别对象,ORM 通常无法在数据库存储和处理环节提供足够效率。


类似 MongoDB 的文档数据库会保留开发人员已经熟悉的对象,因此,不需要类似 ORM 的抽象层。此外,只要学会使用其中一个语言版本的 MongoDB,使用其他语言版本也就不在话下。因此,再也不必为了使用伪英文 SQL 查询而将对象移回。


PostgreSQL 和 Oracle 的确支持 JSON 数据类型,但是靠 JSON 来摆脱 SQL 并不可行。RDBMS 中的 JSON 适用于非托管、非结构化数据,是使用了糟糕的附加查询语法、经过美化的字符串类型。JSON 不适合数据库结构。因此,实际的文档数据库才能满足需求。

减少特定工作负载所需的硬件

现代文档数据库的内部结构非常类似 RDBMS。标准化关系模型中的架构要求所有请求都得到公平对待,而与其不同的是,文档数据库会牺牲其他工作负载来优化特定工作负载的架构。文档模型不仅会将相关行都放在同一个关系模型中,也会将可能要用于特定任务的全部数据放在同一个位置,以这种方式将按索引组织的表格和聚集索引提高到一个新的水平。此处体现的理念是,若拥有一阶数组类型,则关系的重复子属性就不需要放在单独的表(以及类似存储)中。或者,换句话说,可以拥有列类型的“嵌入式表”。


这种所谓的协同位置,即,对弱实体表的隐式联接能够降低从存储区检索数据的成本,因为通常只需读取单一缓存或磁盘位置就可以将对象传回客户端或为其应用筛选条件。


与前述做法不同的是,另一种做法需要识别、找出并读取许多行才能传回相同数据和必要的客户端硬件,从而利用这些行来重构对象。后面这种做法的成本非常高,以至于开发人员会优先考虑让次要且更简单的键值存储(而不是主要数据库)充当缓存。


这些开发人员知道主要数据库无法独自以合理方式满足工作负载需求。文档数据库不需要提前配备外部缓存就能够达成性能目标,但仍能够执行 RDBMS 的全部任务,且效率更高。


效率提升了多少?我按步骤打造了测试装置来确定与使用标准关系数据库相比,使用文档数据库可以提升的效率和节省的成本。在这些测试中,我想要量化为打造同类最佳云托管 RDBMS 与云托管文档数据库 (尤其是 MongoDB Atlas),每美元的事务吞吐量分别为几何。


我选择的用例代表了常见、真实的应用程序,其中的数据集会定期更新,且读取频率更高:以已发布的数据为基础实施英国的汽车检测 (MOT) 系统,及其公共界面和私有界面。


测试结果显示,在 MongoDB Atlas 中创建、更新和读取操作的速度大大提高。总体而言,在实例成本类似的类似指定服务器实例上,MongoDB Atlas 每秒管理的事务大约多 50%。而关系结构越复杂,这个差值就越大,导致联接的成本也越高。


除了基础的实例成本外,在这些测试中,因为利用磁盘的额外费用,关系数据库的每小时运行成本是 Atlas 成本的 200% 到 500% 不等。利用 Atlas 托管系统的成本整体低 3 到 5 倍,非常适合达成特定性能目标。简单地说,Atlas 每美元可推进的事务多得多。


独立测试也证实了文档模型的高效率。总部设于瑞士的软件公司 Temenos 受到全球大型银行和金融机构的青睐,在执行基准测试方面,其拥有超过 15 年的经验。在其最近的测试中,该公司通过 MongoDB Atlas 达到 74,000 的事务处理速率 (TPS)。


这次的测试实现的每核心吞吐量比三年前类似测试的吞吐量高 4 倍,与此同时,使用的基础设施减少 20%。执行这个测试所使用的是生产级基准架构,搭载能够反映生产系统的配置,如高可用性、安全性和专用链接等非功能性要求。


在此测试期间,MongoDB 读取了 74,000 TPS,响应时间为 1 毫秒,此外还引入了另外的 24,000 TPS。此外,由于 Temenos 也使用了文档数据库,过程中没有缓存。所有查询都是直接参照数据库运行。

总结

除非想要在组织中配置供全部应用程序使用的单一数据库,否则建议将工作负载从关系模型移到文档模型。因为这样能够让组织用更少时间、相同数量的开发人员打造出更多数据库,以及大幅减少将数据库投入生产的成本。您所在组织不太可能还没开始使用面向对象的编程。那么,为何您还不开始试试面向对象的文档数据库呢?


免费注册阿里云数据库MongoDB进行试用

阿里云免费试用.png

文档数据库能手 John Page 在加入 MongoDB 前,已在完整堆栈文档数据库技术领域拥有 18 年的经验。目前,他也参与机器人构建,但属于玩票性质。他也测试数据库并撰写相关文章,获得的酬劳用于支撑机器人项目。阅读 John Page 的更多文章


扫码加入钉群,与MongoDB专家一对一沟通,了解更多阿里云MongoDB产品与方案,市场活动及线上培训等内容。

image.png


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
2月前
|
SQL 数据管理 关系型数据库
SQL与云计算:利用云数据库服务实现高效数据管理——探索云端SQL应用、性能优化、安全性与成本效益,为企业数字化转型提供全方位支持
【8月更文挑战第31天】在数字化转型中,企业对高效数据管理的需求日益增长。传统本地数据库存在局限,而云数据库服务凭借自动扩展、高可用性和按需付费等优势,成为现代数据管理的新选择。本文探讨如何利用SQL和云数据库服务(如Amazon RDS、Google Cloud SQL和Azure SQL Database)实现高效的数据管理。通过示例和最佳实践,展示SQL在云端的应用、性能优化、安全性及成本效益,助力企业提升竞争力。
45 0
|
5月前
|
运维 数据挖掘 测试技术
如何评估数据库的成本效益
【5月更文挑战第21天】 如何评估数据库的成本效益
97 3
|
16天前
|
NoSQL 关系型数据库 MySQL
微服务架构下的数据库选择:MySQL、PostgreSQL 还是 NoSQL?
在微服务架构中,数据库的选择至关重要。不同类型的数据库适用于不同的需求和场景。在本文章中,我们将深入探讨传统的关系型数据库(如 MySQL 和 PostgreSQL)与现代 NoSQL 数据库的优劣势,并分析在微服务架构下的最佳实践。
|
18天前
|
存储 SQL 关系型数据库
使用MySQL Workbench进行数据库备份
【9月更文挑战第13天】以下是使用MySQL Workbench进行数据库备份的步骤:启动软件后,通过“Database”菜单中的“管理连接”选项配置并选择要备份的数据库。随后,选择“数据导出”,确认导出的数据库及格式(推荐SQL格式),设置存储路径,点击“开始导出”。完成后,可在指定路径找到备份文件,建议定期备份并存储于安全位置。
158 11
|
2月前
|
弹性计算 关系型数据库 数据库
手把手带你从自建 MySQL 迁移到云数据库,一步就能脱胎换骨
阿里云瑶池数据库来开课啦!自建数据库迁移至云数据库 RDS原来只要一步操作就能搞定!点击阅读原文完成实验就可获得一本日历哦~
|
2月前
|
关系型数据库 MySQL 数据库
RDS MySQL灾备服务协同解决方案构建问题之数据库备份数据的云上云下迁移如何解决
RDS MySQL灾备服务协同解决方案构建问题之数据库备份数据的云上云下迁移如何解决
|
13天前
|
存储 SQL 关系型数据库
MySQL的安装&数据库的简单操作
本文介绍了数据库的基本概念及MySQL的安装配置。首先解释了数据库、数据库管理系统和SQL的概念,接着详细描述了MySQL的安装步骤及其全局配置文件my.ini的调整方法。文章还介绍了如何启动MySQL服务,包括配置环境变量和使用命令行的方法。最后,详细说明了数据库的各种操作,如创建、选择和删除数据库的SQL语句,并提供了实际操作示例。
57 13
MySQL的安装&数据库的简单操作
|
19天前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
3天前
|
Oracle NoSQL 关系型数据库
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
14 2
|
9天前
|
SQL 关系型数据库 MySQL
创建包含MySQL和SQLServer数据库所有字段类型的表的方法
创建一个既包含MySQL又包含SQL Server所有字段类型的表是一个复杂的任务,需要仔细地比较和转换数据类型。通过上述方法,可以在两个数据库系统之间建立起相互兼容的数据结构,为数据迁移和同步提供便利。这一过程不仅要考虑数据类型的直接对应,还要注意特定数据类型在不同系统中的表现差异,确保数据的一致性和完整性。
22 4
下一篇
无影云桌面