查询执行

查询计划

SELECT R.id, S.cdate
  FROM R JOIN S
	ON R.id = S.id
 WHERE S.value > 100	
  • 所有运算符被安排在一棵树上
  • 数据从树叶流向树根
  • 根节点的输出是查询的结果

处理模型

数据库管理系统的处理模型定义了该系统如何执行一个查询计划。

  • 不同的工作负载有不同的权衡

方法一:迭代模型(Iterator Model)
方法二:物化模型(Materialization Model)
方法三:矢量/批处理模型(Vectorized/Batch Model)

迭代器模型

每个查询计划运算符都实现了Next函数。

  • 在每次调用时,运算符返回一个元组,如果没有更多的元组,则返回空标记(null marker)
  • 运算符实现一个循环,该循环调用其子节点的next函数来检索元组并处理它们

该模型也称为Volcano流水线模型。


[例]
迭代模型的实现伪代码如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


几乎所有允许元组流水线的数据库管理系统都使用该模型。
在这里插入图片描述


有些运算符必须阻塞,直到它们的子节点发出了所有元组。

  • joins, Subqueries, Order By

输出控制很容易用这种方法工作。例如 limit子句,在父节点处需要10个tuple,那么它就只会调用10次子节点的next函数。

物化模型

每个运算符一次性处理所有输入,然后一次性发出所有输出。

  • 操作符将其输出“物化”为单个结果
  • DBMS可以将提示下推,以避免扫描过多的元组(比如limit子句,如果不告诉子节点需要多少tuple,就会收到非常多tuple)
  • 可以发送物化的行或单个列

输出可以是整个元组(NSM)或列的子集(DSM)


在这里插入图片描述


物化模型对于OLTP型的工作负载更好,因为查询一次只访问少量的元组。

  • 降低执行/协调开销
  • 更少的函数调用

对于中间结果较大的OLAP查询不太好。
在这里插入图片描述

矢量模型

就像迭代模型,每个运算符实现这个模型中的Next函数。
每个运算符发出一批元组,而不是一个元组。

  • 运算符内部循环一次处理多个tuple
  • 批处理的大小可能因硬件或查询属性而异

在这里插入图片描述


向量模型非常适合OLAP查询,因为它大大减少了每个运算符的调用次数。
它允许运算符使用矢量化(SIMD)指令来分批处理元组。
在这里插入图片描述

计划处理的方向

方法一:自顶向下

  • 从根开始,从它的子节点中“拉取”数据
  • 元组总是与函数调用一起传递

方法二:自底向上

  • 从叶节点开始,将数据推送到它们的父节点
  • 允许对流水线中的缓存/寄存器进行更严格的控制

访问方法

访问方法是DBMS访问表中存储的数据的方法。

  • 在关系代数中没有定义

三种基本方法:

  • 顺序扫描
  • 索引扫描
  • 多索引 / “位图“索引

顺序扫描

for page in table.pages:
	for t in page.tuples:
		if evalPred(t):
			//Do something!

对于表中的每一页:

  • 从缓冲池中检索它
  • 迭代每个元组并检查该元组是否符合查询的条件

DBMS维护一个游标,它跟踪它检查的最后一页/slot

优化

这几乎总是DBMS执行查询所能做的最糟糕的事情。

顺序扫描优化:

  • 预提取(Prefetching)
  • Buffer Pool Bypass
  • 并行(Parallelization)
  • Zone Maps
  • 延迟物化
  • 堆聚簇(Heap Clustering)
ZONE MAPS

ZONE MAPS为数据库表预先计算其属性的聚合值。DBMS首先检查ZONES MAPS,以决定是否要访问该表。

[例]有如下的一个表,该表只有一列
在这里插入图片描述
假设有一个查询:

SELECT * FROM table
 WHERE val > 600

DBMS在进行循环扫描前,会先去查看Zone Map,然后发现这个表的MAX值为400,所以这个表里肯定没有满足条件的tuple,便不会去遍历该表。

Zone Map存储在哪里呢?可以和表一起存储在page里,也可以用专门的page把Zone Map集中存储。Zone Map也许会写到磁盘上,但大部分时候存放在内存中。

Zone Map的一个问题在于维护。每当更新过数据库表,就需要对Zone Map重新计算,这个成本并不小。所以Zone Map适合于OLAP型的数据库,而不适合OLTP型的数据库。

延迟物化

列式存储的DBMS可以延迟缝合元组(元组的属性值分布在不同的page当中,最终的结果需要读取多个page,然后拼合成完整的tuple)。

[例]
下面的foo表的三个属性a,b,c分别存储在不同的page中
在这里插入图片描述


执行select操作时,先读取a所在的page,进行筛选,系统可以识别出父节点需要的属性,在这里,它的父节点join不需要用到属性a,因此不返回具体的a值,而仅仅返回这个tuple在表中的位置(Offset)。可以看到,这样做的好处在于可以避免传送多余的数据。
在这里插入图片描述


同理,在执行join操作时,读取b所在的page,它同样知道父节点不需要b的值,所以返回元组的位置
在这里插入图片描述


最后根节点在给出结果时,才去page里读取出具体的数据拼合成tuple。
在这里插入图片描述

堆聚簇(Heap Clustering)

如图,这堆page里的tuple已经按照聚簇索引排好序了,这些page本身也是有序的。
如果查询使用聚簇索引属性访问元组,那么DBMS可以直接跳转到它需要的page。

索引扫描

DBMS挑选一个索引来查找查询所需的元组。

使用哪个索引取决于:

  • 索引包含哪些属性
  • 查询引用哪些属性
  • 属性值域
  • 谓词条件(大于,小于或等于)
  • 索引是否具有唯一键或非唯一键

[例]
假设我们有一个包含100个元组和两个索引的表:

  • 索引1:age
  • 索引2:dept
SELECT * FROM students 
 WHERE age < 30
   AND dept = 'CS'
   AND country = 'CN'

使用哪个索引取决于表中的数据是啥样的。

情景1
30岁以下的有99人,但CS学院的只有2人。

这里很明显应该选择dept作为索引,否则要用循环扫描来在99人中找2个CS学院的人。

情景二
CS学院的有99人,但30岁以下的只有2人。

选择age作为索引。

DBMS要试图避免读取不需要的数据,其中也包括了探测索引的成本。DBMS应该意识到,如果选择了一个选择性不高的属性作为索引,就会为遍历索引或查找索引付出代价。

多索引扫描

如果有多个可以供DBMS用来查询的索引:

  • 使用每个索引分别计算出tuple的ID集合
  • 基于查询的谓词组合这些集合(并或交)
  • 检索tuple并应用其它剩余的谓词条件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值