Atitit 读取数据库的api orm  SQL Builder  sql对比

目录

1.1. 提高生产效率的 ORM 和 SQL Builder 1

1.2. SQL Builder 在 SQL 和项目可维护性之间取得了比较好的平衡。 4

1.3. Sql更加通用 5

  1. 提高生产效率的 ORM 和 SQL Builder

在 Web 开发领域常常提到的 ORM 是什么?我们先看看万能的维基百科:

对象关系映射(英语:Object Relational Mapping,简称 ORM,或 O/RM,或 O/Rmapping),是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。

最为常见的 ORM 实际上做的是从 db 到程序的类或结构体这样的映射。所以你手边的程序可能是从 MySQL 的表映射你的程序内的类。我们可以先来看看其它的程序语言里的 ORM 写起来是怎么样的感觉:

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

完全没有数据库的痕迹,没错 ORM 的目的就是屏蔽掉 DB 层,实际上很多语言的 ORM 只要把你的类或结构体定义好,再用特定的语法将结构体之间的一对一或者一对多关系表达出来。那么任务就完成了。然后你就可以对这些映射好了数据库表的对象进行各种操作,例如 save,create,retrieve,delete。

至于 ORM 在背地里做了什么阴险的勾当,你是不一定清楚的。使用 ORM 的时候,我们往往比较容易有一种忘记了数据库的直观感受。举个例子,我们有个需求:向用户展示最新的商品列表,我们再假设,商品和商家是1:1的关联关系,我们就很容易写出像下面这样的代码:

# 伪代码
shopList := []
for product in productList {
    shopList = append(shopList, product.GetShop)
}

当然了,我们不能批判这样写代码的程序员是偷懒的程序员。因为 ORM 一类的工具在出发点上就是屏蔽 sql,让我们对数据库的操作更接近于人类的思维方式。这样很多只接触过 ORM 而且又是刚入行的程序员就很容易写出上面这样的代码。

这样的代码将对数据库的读请求放大了 N 倍。也就是说,如果你的商品列表有 15 个 SKU,那么每次用户打开这个页面,至少需要执行 1(查询商品列表)+ 15(查询相关的商铺信息)次查询。这里 N 是 16。

如果你的列表页很大,比如说有 600 个条目,那么就至少要执行 1+600 次查询。如果说你的数据库能够承受的最大的简单查询是 12 万 QPS,而上述这样的查询正好是最常用的查询的话,实际上能对外提供的服务能力是多少呢?是 200 qps!互联网系统的忌讳之一,就是这种无端的读放大。

当然,也可以说这不是 ORM 的问题,如果手写 sql 还是可能会写出差不多的程序,那么再来看两个 demo:

o := orm.NewOrm()
num, err := o.QueryTable("cardgroup").Filter("Cards__Card__Name", cardName).All(&cardgroups)

很多 ORM 都提供了这种 Filter 类型的查询方式,不过实际上在某些 ORM 背后甚至隐藏了非常难以察觉的细节,比如生成的 SQL 语句会自动 limit 1000。
也许喜欢 ORM 的读者读到这里会反驳了,你是没有认真阅读文档就瞎写。

是的,尽管这些 ORM 工具在文档里说明了 All 查询在不显式地指定 Limit 的话会自动 limit 1000,但对于很多没有阅读过文档或者看过 ORM 源码的人,这依然是一个非常难以察觉的“魔鬼”细节。

喜欢强类型语言的人一般都不喜欢语言隐式地去做什么事情,例如各种语言在赋值操作时进行的隐式类型转换然后又在转换中丢失了精度的勾当,一定让你非常的头疼。所以一个程序库背地里做的事情还是越少越好,如果一定要做,那也一定要在显眼的地方做。比如上面的例子,去掉这种默认的自作聪明的行为,或者要求用户强制传入 limit 参数都是更好的选择。

除了 limit 的问题,我们再看一遍这个下面的查询:

num, err := o.QueryTable("cardgroup").Filter("Cards__Card__Name", cardName).All(&cardgroups)

可以看得出来这个 Filter 是有表 join 的操作么?当然了,有深入使用经验的用户还是会觉得这是在吹毛求疵。但这样的分析想证明的是,ORM 想从设计上隐去太多的细节。而方便的代价是其背后的运行完全失控。这样的项目在经过几任维护人员之后,将变得面目全非,难以维护。

当然,我们不能否认 ORM 的进步意义,它的设计初衷就是为了让数据的操作和存储的具体实现所剥离。但是在上了规模的公司的人们渐渐达成了一个共识,由于隐藏重要的细节,ORM 可能是失败的设计。其所隐藏的重要细节对于上了规模的系统开发来说至关重要。

相比 ORM 来说,

  1. SQL Builder 在 SQL 和项目可维护性之间取得了比较好的平衡。

首先 sql builer 不像 ORM 那样屏蔽了过多的细节,其次从开发的角度来讲,SQL Builder 简单进行封装后也可以非常高效地完成开发,举个例子:

where := map[string]interface{} {
    "order_id > ?" : 0,
    "customer_id != ?" : 0,
}
limit := []int{0,100}
orderBy := []string{"id asc", "create_time desc"}
orders := orderModel.GetList(where, limit, orderBy)

写 SQL Builder 的相关代码,或者读懂都不费劲。把这些代码脑内转换为 sql 也不会太费劲。所以通过代码就可以对这个查询是否命中数据库索引,是否走了覆盖索引,是否能够用上联合索引进行分析了。

说白了 SQL Builder 是 sql 在代码里的一种特殊方言,如果你们没有 DBA 但研发有自己分析和优化 sql 的能力,或者你们公司的 DBA 对于学习这样一些 sql 的方言没有异议。那么使用 SQL Builder 是一个比较好的选择,不会导致什么问题。

另外在一些本来也不需要 DBA 介入的场景内,使用 SQL Builder 也是可以的,例如要做一套运维系统,且将 MySQL 当作了系统中的一个组件,系统的 QPS 不高,查询不复杂等等。

一旦你做的是高并发的 OLTP 在线系统,且想在人员充足分工明确的前提下最大程度控制系统的风险,使用 SQL Builder 就不合适了

  1. Sql更加通用

Atitit 读取数据库的api orm SQL Builder sql对比 目录 1.1. 提高生产效率的 ORM 和 SQL Builder 1 1.2. SQL Builder 在 SQL相关推荐

  1. python pandas 读取数据库_数据分析-pandas从数据库读取数据

    数据分析-pandas从数据库读取数据 使用pandas读取数据到DataFrame,对于只是数据分析来说,重点是读取数据,读取数据过程越简单越好,并不需要写得很复杂显得自己很厉害的样子.最好就是代码 ...

  2. python读取数据库数据、并保存为docx_Python从数据库读取大量数据批量写入文件的方法...

    Python从数据库读取大量数据批量写入文件的方法 使用机器学习训练数据时,如果数据量较大可能我们不能够一次性将数据加载进内存,这时我们需要将数据进行预处理,分批次加载进内存. 下面是代码作用是将数据 ...

  3. 绘制图形可以使用什么python数据库_python 读取数据库并绘图的实例

    python 读取数据库并绘图的实例 1.安装相应的库文件 sudo apt-get install python-mysqldb 2.数据库操作 import MySQLdb db = MySQLd ...

  4. jdbc 获取mysql表注释_jdbc读取数据库,表相关信息(含注释)

    读取数据库中的所有的表名 private Set getTableNameByCon(Connection con) { Set set = new HashSet(); try { Database ...

  5. 读取数据库信息构建视图字段的备注信息,方便程序代码生成

    在很多情况下,我们开发都需要有一个快速的代码生成工具用来提高开发效率,代码生成工具很多信息都是读取数据库的表.视图等元数据进行对象表信息的完善,有了这些信息,我们就可以在普通的实体类代码里面添加属性字 ...

  6. 【学习笔记】JDBC:java提供的专门操纵数据库的API JDBC驱动程序的类型 JDBC常用的类与接口

    JDBC技术 JDBC的全称是Java DataBase Connectivity,是一套面向对象的应用程序接口,指定了统一的访问各种关系型数据库的标准接口,JDBC是一种底层的API,因此访问数据库 ...

  7. 基于Java线程池读取数据库中数据(学习+运用)

    基于Java线程池读取数据库中数据(学习+运用) 以下是学习内容 Main.java import java.util.concurrent.ArrayBlockingQueue; import ja ...

  8. json怎么读取数据库_如何:使用Json插入数据库并从中读取

    json怎么读取数据库 在本文中,我们将为Speedment创建一个插件,该插件使用Gson生成序列化和反序列化逻辑,从而使其在数据库实体和JSON字符串之间进行映射非常容易. 这将有助于展示Spee ...

  9. php如何逐条读取数据库,php从数据库中读取特定的行(实例)

    有的时候我们需要从数据库中读取特定的数据,来检验用户的输入,这个时候需要执行的sql语句是: select * from table_name where id='num'; 需要执行这样的一个语句. ...

  10. java空值转datetime,解决Java (Spring boot) 读取数据库字段,datetime 格式为null,抛出异常 Zero date value prohibited...

    使用 Mapper 读取数据库数据时,因时间字段为 null, Java设置该字段为 Instant, 在Mapper转为 List时出了错误,如果使用 List则不抛异常. 但实际情况我们还是希望使 ...

最新文章

  1. 智能连接:5G、AI和IoT的组合如何改变美洲
  2. 20154318_王秀飞 Exp2 后门原理与实践
  3. Leetcode 38.外观数列 (每日一题 20210702)
  4. Ethermint部署及框架解析
  5. storm目录结构及在zk中的目录结构
  6. 如何禁止SAP Fiorigateway系统上的病毒扫描
  7. word List 47
  8. Shell入门(五)之参数
  9. Activiti绩效对决
  10. kali linux 截图位置,Kali Linux中使用shutter截图工具 | CN-SEC 中文网
  11. ACM MM2018 Best Paper 被华人包揽
  12. 在页面加载后执行任务
  13. 机器人庄园作文_2018年6月四级作文热点话题预测:高端的机器人
  14. Android 系统签名打包方法
  15. uboot移植主要思路
  16. c语言实现滑动窗口类,C语言模拟滑动窗口协议
  17. 二进制 转换 .java_如何在Java程序中将二进制转换为十进制?
  18. MATLAB中对tif格式栅格影像读取-保存
  19. 中国经济能否率先复苏
  20. 【构建ML驱动的应用程序】第 5 章 :训练和评估模型

热门文章

  1. c++ new操作符(new operator)、operator new、placement new 、operator new[] 及相对应的delete 操作符、operator delete
  2. unix 网络编程全解
  3. html5控制字大小的代码,js根据字符串长度控制字体大小代码
  4. BOOST库介绍(六)——容器
  5. 数据分析:AI智能科技影响下,电话机器人实现落地
  6. [译] 在浏览器里使用 TenserFlow.js 实时估计人体姿态
  7. 透析JMS、MQ看看应用与应用的底层如何完成通信
  8. HDOJ(HDU) 2097 Sky数(进制)
  9. 谁让APP工程师产生了泡沫?
  10. 动手才能进步(冒泡法示例)