数据库操作的经济效益

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 转为使用文档数据库并实施恰当的数据建模技术,就有机会提高效率、节省资金。

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


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

  • 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
相关文章
|
3月前
|
SQL 数据管理 关系型数据库
SQL与云计算:利用云数据库服务实现高效数据管理——探索云端SQL应用、性能优化、安全性与成本效益,为企业数字化转型提供全方位支持
【8月更文挑战第31天】在数字化转型中,企业对高效数据管理的需求日益增长。传统本地数据库存在局限,而云数据库服务凭借自动扩展、高可用性和按需付费等优势,成为现代数据管理的新选择。本文探讨如何利用SQL和云数据库服务(如Amazon RDS、Google Cloud SQL和Azure SQL Database)实现高效的数据管理。通过示例和最佳实践,展示SQL在云端的应用、性能优化、安全性及成本效益,助力企业提升竞争力。
73 0
|
6月前
|
运维 数据挖掘 测试技术
如何评估数据库的成本效益
【5月更文挑战第21天】 如何评估数据库的成本效益
121 3
|
14天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
29 1
|
16天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
30 4
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
64 3
Mysql(4)—数据库索引
|
23天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
118 1
|
25天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
77 2
|
28天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
104 4
|
11天前
|
运维 关系型数据库 MySQL
安装MySQL8数据库
本文介绍了MySQL的不同版本及其特点,并详细描述了如何通过Yum源安装MySQL 8.4社区版,包括配置Yum源、安装MySQL、启动服务、设置开机自启动、修改root用户密码以及设置远程登录等步骤。最后还提供了测试连接的方法。适用于初学者和运维人员。
106 0
|
1月前
|
存储 关系型数据库 MySQL
如何在MySQL中创建数据库?
【10月更文挑战第16天】如何在MySQL中创建数据库?
下一篇
无影云桌面