点上面“东哥IT笔记”,关注并星标

每天一篇业界最新技术分享


在前面几篇文章中,我们已经介绍了总体构架,客户端管理和查询管理。在查询管理中,有一个很重要的部分我们没有介绍,那就是查询优化,这也是本文所要介绍的内容。

所有的现代数据库都是基于cost进行优化的(Cost Based Optimization, CBO)。总体的思想就是看每一个操作的cost是多少,然后找出一个cost最小的路径来执行这些操作并获取结果。

本文会首先以最常的三种join为例来进行介绍,看看哪怕是简单的join,它背后的优化是如何进行工作的。在这些例子中,我们关注时间复杂度,这个其实和真实的数据库优化器的计算是有所不同的,它真实会关注CPU消耗,磁盘I/O消耗以及内存的需求。时间复杂度和CPU消耗其实是差不多的,我们这种懒人就直接使用时间复杂度来进行分析了。当然有时候我们还需要考虑磁盘的I/O消耗,因为很多时候真正的瓶颈就是在于磁盘I/O而不是CPU的使用率。

JOIN的操作

我们会来看三个最常见的join操作,merger Join, Hash Join以及Nested Loop Join。在正式开始之前,我们来引入两个名词,outer relation和inner relation,很简单outer relation就是join左边的数据集,inner relation就是join右边的数据集。比如A JOIN B, 我们把A称之为outer relation而B称之为inner relation。并且假设outer relation有N个元素,inner relation有M个元素。我们可以很容易知道A JOIN B和B JOIN A其实是不太相同的。

Nested loop join

Nested loop join是最简单的一种情况

它的思想是,对每一个在outer ralation中的行,都去看是否在inner relation中存在。要是从伪码的角度来看,它是这样实现的:

nested_loop_join(arrayouter, array inner)  for each row a in outer    for each row b in inner      if (match_join_condition(a,b))        write_result_in_output(a,b)      end if    end for   end for

其实说白了就是全遍历的循环,所以时间复杂度是O(N*M)。

从磁盘I/O的角度来看,对每一个在outer relation中的行(N),都需要从inner relation中读出M行。所以就需要从磁盘读取N + N*M次。但是假如inner relation的行比较少,我们就不需要每次都从磁盘中读取,而是可以把它保存在memory中,这种情况下磁盘的读取就会少很多,只需要N+M次。所以,这种情况下,我们希望N的大小足够小,这样就可以使用memory来保存而不需要每次都进行磁盘的读取。

当然了,假如inner relation能够有index,那么它读取的磁盘I/O的次数会更少。

那么假如inner relation的数据很大,不能够保存在memory中怎么办呢,是不是就一定要进行N+N*M次的磁盘读取呢?其实并不尽然,这里有一个常见的优化方法,就是每次都读一个bunch的行,然后把这些行放到memory中,让他们和outer relation先进行匹配,等他们做完了,在读下一个bunch,这样一来,最终磁盘I/O的访问就得到了优化。

下面是伪码的实现:

//improved version to reduce the disk I/O.nested_loop_join_v2(fileouter, file inner)  for each bunch ba in outer  // ba is now in memory    for each bunch bb in inner        // bb is now in memory        for each row a in ba          for each row b in bb            if (match_join_condition(a,b))              write_result_in_output(a,b)            end if          end for       end for    end for   end for

有了这种优化之后,时间复杂度还是一样的,但是磁盘I/O的访问次数就变成了 bunch的次数(outer)+bunch 次数(outer)*bunch次数(inner)。所以总得来说可以通过增加bunch的大小来减少bunch的次数,这样的磁盘I/O访问就会变小。

Hash Join

Hash join相比上面的nested loop join稍微复杂一点,但是它的cost在大多数情况下则会小很多。

Hash Join的思想如下:

  1. 从inner relation中得到所有的元素

  2. 创建一个in     memory的hash表

  3. 从outer     realtion一个一个的得到元素

  4. 计算每一个的hash值,然后找到inner     relation中对应的bucket

  5. 然后在bucket中查看是否有匹配的元素

在计算相关的时间复杂度之前,我们来做一些假设:

  • Inner     relation被分成了X个bucket

  • Hash函数针对outer     relation和inner relation都可以均匀分布,也就是说每一个bucket的大小差不多

  • 在Bucket内部查找匹配的时候的消耗就是bucket的大小

所以时间复杂度就是 (M/X)*N + 创建hash表的cost + N*hash函数的cost。假如hash函数所创造的bucket的大小足够小,那么其实时间复杂度相当于O(M+N)。

另外还有一种hash join的算法,对内存来说很友好,但是磁盘I/O消耗则大一些:

  1. 为inner relation和outer relaition都创建hash表

  2. 把他们放到磁盘中

  3. 然后把两者通过一个bucket一个bucket地进行比较

Merge Join

Merge Join是唯一的会产生排好序的结果的Join。

Merge Join可以分成两步:

  • (可选)排序:两个输入都按照join key进行排序

  • Merge     join:把排好序的两者merge到一起

排序

使用merge sort(算法)进行排序是一个很好的选择,当然假如内存不是问题,我们还会有更好的方法。

只是有时候,很多时候其实已经都排好序了,比如:

  • 表格本身就排好序,比如join的表格是基于index进行组织的

  • join的条件是表的index

  • join的一方是一个临时的结果,但这个结果是已经排好序的

Merge Join

总得思想和merge sort是类似的,只是这里我们只选择两者相等的元素:

  1. 比较两个relation中的元素

  2. 假如相等,把他们放到result中,然后比较两者中的下一个元素

  3. 不相等,就比较小的relation中的下一个元素

  4. 重复上面步骤

这是一个很简单的示例,现实情况可能会比这个复杂一点,比如他们中间有多个相等的内容如何比较等等。不过我们就先来看看这个简单的情况。

先来看看时间复杂度,假如两个relation是都已经排序了,那么复杂度就是O(N+M)。假如两者都需要进行排序,那么复杂度就是 O(N*Log(N) +M*Log(M))

三种join的比较

毫无疑问,这三个join都有其使用的场景,没有哪一个是必然比另外两个好的(废话,否则为什么要三种),选择哪一种join其实取决于很多因素:

  • 空闲memory的数量:假如没有足够的memory,显然没法使用hash     join。

  • 两个数据集的大小:比如你有一个很大的表和一个很小的表进行join,那么nested     loop可能是一个比hash join更快的选择,因为你不需要花费时间去创建hash表。而假如你的两个表都很大,那么nested     loop可能需要非常耗费CPU。

  • index:假如有B+ TREE的index,那么merge join可能是一个更好的选择

  • 结果需要排序:假如你所需要的结果要求排序,那么可能选择merge     join更好,因为你终归是要进行排序的。

  • 假如relation已经排序了:这个没啥好说的,merge     join是一个不错的选择。

  • join的类型:比如你使用的是相等join还是inner     join, outer join或者self-join等等,这些都会影响最终的选择。

  • 数据的分布:比如你想join名字中的姓,因为有很多重复的数据,那么你使用hash     join可能就会遇到很多问题。

  • 你是否想让多进程/线程执行join操作:这也会影响最终join类型的选择。

本文介绍了查询优化中两个表的join操作,我们了解了三种常见的join类型: nested loop join, merge join以及hash join,并把他们的原理和使用场景进行了解释。不过总得来说我们还是使用的最简单的两个表join来进行说明的,那么假如是多个表的join该如何处理呢,我们将会在下一篇文章中进行介绍。

oracle如何读取到从n行到m行的数据_关系型数据库进阶之查询优化相关推荐

  1. 使用函数BAPISDORDER_GETDETAILEDLIST读取S/4HANA中Sales Order行项目数据

    事务码MM03查看物料主数据,如下图所示的行项目数据,包含物料ID,描述信息,数量,单价等等: 使用如下代码进行行项目读取: DATA: ls_read TYPE order_view, lt_ite ...

  2. javaScript读取excel文件中某几行的数据

    一.介绍 这份代码借鉴了YouTube上的这个视频:https://www.youtube.com/watch?v=OK60UdWyUdE代码,讲解得很棒,让我一个不太懂javasript的小白明白了 ...

  3. oracle取时间最近的一条数据_当数据库最近一直卡顿时,第一时间应该用这条sql来分析...

    概述 国庆节偷个懒,分享一个关于锁的实用sql,不过统计是实时的,如果要查看一段时间的,建议将结果插入一张中间表. 一键获取锁相关信息 SELECT mm.inst_id, mm.sid, mm.TY ...

  4. 从oracle中读取图片,Pb从oracle中读取和保存图片

    Pb从oracle中读取和保存图片 (2008-12-12 12:23:20) 转载 分类:编程 标签: it //保存图片 //选择文件 string pname, fname integer va ...

  5. oracle proedure 文件_关于oracle存储过程读取文件

    你的位置: 问答吧 -> Oracle -> 问题详情 关于oracle存储过程读取文件 问题:我知道只能读取固定目录的文件,我想问的是 1,文件名可以通过参数传入存储过程中吗? 2,怎么 ...

  6. spark Java oracle,spark2.x由浅入深深到底系列六之RDD java api用JdbcRDD读取关系型数据库...

    课程咨询以及领取大额优惠请加微信:bigdatatang01 以下是用spark RDD java api实现从关系型数据库中读取数据,这里使用的是derby本地数据库,当然可以是mysql或者ora ...

  7. java oracle 结果集_java如何显示从oracle中读取的全部结果集?

    java如何显示从oracle中读取的全部结果集?如题,并不是在程序中预先设置好字段然后读取字段,而是把结果集全部显示出来,就相当于做了一个类似sqlplus的界面,我把代码写成这样,程序虽不出... ...

  8. poi读取Excel文件执行到row.getCell(0).getStringCellValue()异常

    环境说明 POI:poi.3.1.1.jar Excel文件: 具体问题 测试导入Excel文件,并将文件数据批量导入数据库功能时,一直无法成功导入,不打断点没有抛任何异常,部分代码如下: /*** ...

  9. 关系型数据库 和 非关系型数据对比 以及 MySQL与Oracle对比

    一.关系型数据库 关系型数据库,是指采用了关系模型来组织数据的数据库.     关系模型1970年提出的,关系模型的概念得到了充分的发展并逐渐成为主流数据库结构的主流模型.     简单来说,关系模型 ...

最新文章

  1. 女友问粉丝过万如何庆祝,我发万字长文《保姆级大数据入门篇》感恩粉丝们支持,学姐|学妹|学弟|小白看了就懂
  2. linux python3安装包_Linux下安装python3及相关包
  3. 内存分配_go内存分配管理
  4. np.reshape带给我的内存错误
  5. A review of 3D/2D registration methods for image-guided interventions(2)
  6. 禁止存放到内存_暴雨 ! 神木能源局:关于煤炭运输及存放的通告
  7. Python + Appium 环境搭建
  8. mac上如何安装oracle,在mac上安装oracle instant client 和 sqlplus
  9. 利用c语言实现函数信号发生器,基于51单片机函数信号发生器完整论文下载 带源码 原理图...
  10. 方差(variance)、标准差(Standard Deviation)、均方差、均方根值(RMS)、均方误差(MSE)、均方根误差(RMSE)
  11. 河北画报杂志河北画报杂志社河北画报编辑部2022年第20期目录
  12. 北京科技大学计算机专业选课要求,北京科技大学2020年拟在北京招生专业选考科目要求...
  13. 达梦数据库逻辑备份(dexp/dimp)
  14. 关于批量插入一组数据
  15. java的nullpoint_Java中避免NullPointerException的方法总结
  16. 演绎另类黑客马拉松,机智云中国第二届智能硬件36小时开发大赛完美收官
  17. 电视剧《大人物》40全集在线观看
  18. Nginx系列:后端服务应用健康检测
  19. CorelDRAW文件损坏的几种解决方法
  20. 生活需要仪式感,欧蓝德幸福照相馆带你发现身边的幸福

热门文章

  1. win11文件夹打开延迟怎么办 Windows11文件打开延迟的解决方法
  2. php无重复字符的最长子串,无重复字符的最长字串问题
  3. 什么是陀螺仪的dr算法_PID控制器调参工具——DR-PID Tuning(Matlab GUI)
  4. jupyter 导入文件路径_更改jupyter notebook默认存储路径
  5. python交互式数据可视化_基于Python实现交互式数据可视化的工具,你用过几种?...
  6. iphone怎么重启_iPhone看完这个都要卡死机!这串神秘代码,是真的有毒
  7. activiti bpmn 安装不上_OTC弧焊工作站问题集-Win7 64位系统安装Step7 MicroWIN
  8. 微信小程序富文本组件mp-html
  9. java加法运算器界面_Java 接口实现计算器加减乘除(字符交互界面)
  10. Linux(乌班图 )系统下安装jdk 和eclipse开发IDE