CMU15-721 Note4 | Query Execution & Processing I
文章发布时间:
最后更新时间:
文章总字数:
预计阅读时间:
页面浏览: 加载中...
最后更新时间:
文章总字数:
1.1k
预计阅读时间:
3 分钟
页面浏览: 加载中...
1. 操作节点(operator)执行
在OLAP系统中,顺序扫描是最基础最主要的查询执行方法。通过扫描大块数据并采取必要的操作来获取需要的结果。
为了高效的查询执行,需要最小化从硬盘或远程对象存储获取的数据量,同时最大化对硬件的利用。
Andy’s (unscientific) Top-3 execution optimizations
- 数据并行(向量化)
- 任务并行(多线程)
- 代码专业化(Pre-Compiled/JIT)
3种加速加速查询的技术:
- 减少指令数量
- 减少每条指令的CPU周期:最大化本地处理,减少cache miss和栅栏
- 并行执行
2. 查询执行
查询执行基于生成的查询计划。相关术语:
- 一个查询计划是操作节点的DAG
- 一个操作节点实例是操作节点对唯一数据段的调用
- 一个任务是单个或多个操作节点实例的序列
- 一个任务集是逻辑管道(Pipeline)的可执行任务的集合
3. MonetDB/X100 Analysis
提供对OLAP工作负载上内存中DBMS的执行瓶颈的低级别分析。研究结果表明,当时的DBMS针对现代CPU架构是如何错误地设计的。
3.1. CPU概览
CPU将指令组织到流水线阶段,目标是通过屏蔽无法在单个周期内完成的指令中的延迟,使处理器的所有部分在每个周期内保持繁忙。超标量处理器支持多条流水线,将会在一个周期内并行执行相互无依赖的多条指令(乱序执行)。
3.2. 数据库系统中CPU的问题
- 依赖:如果一条指令依赖于另一条指令,CPU不能将其立即推入流水线
- 分支预测:CPU尝试预测程序分支并将其放入流水线。如果预测出错,需要抛弃所有推测出的工作并清空流水线。比如:选择性扫描导致的分支预测错误;不同数据类型支持导致的过多指令。(因为分支预测,通常三目运算和switch比if-else性能更好)
4. 处理模型
两种处理方向:
- 自顶向下
- 从子节点拉取数据,父节点在子节点返回元组前会阻塞
- 总是使用调用函数的方式传递元组
- 使用
LIMIT
控制输出非常简单 Next()
通常是虚函数,会带来额外开销(虚函数表)- 调用
Next()
时通常会有分支开销
- 自底向上
- 子节点向上推送数据
- 可以在for循环中融合操作节点,支持流水线中缓存和寄存器的更紧密的控制
- 无法确切控制中间结果集大小
- 某些操作节点很难实现
4.1. 迭代器模型(火山/流水线模型)
1 |
|
- 几乎所有数据库都会使用迭代器模型
- 实现和调试简单
- 输出控制简易
- 允许CPU流水线
- 管道中断器:某个子节点没有输出所有数据前不会产生输出(数据流会在此阻塞)
4.2. 物化模型
1 |
|
- 每节点都会输出全部值
- 数据库可以将诸如
LIMIT
的限制下推以避免扫描过多数据 - 可以输出元组数组或者列数组
- 实际上更利好OLTP数据库,因为TP查询单次只请求很少量的元组
- 执行负载低
- 函数调用少
4.3. 向量/批处理模型
1 |
|
- 每个操作节点节点都输出一批元组而不是单个元组 节点的内部循环单次处理多个元组 每批元组数量基于硬件或者查询规模变化 每批元组每列使用自己的null-bitmap而不是bool数组
- 利好OLAP数据库
- 极大的减少了每个操作节点节点的调用数量
- 允许CPU乱序执行和SIMD
- 无数据和控制依赖
- 热指令缓存
5. 过滤表示
- Selection Vectors
- 适用于稀疏的选择
- 一般会直接根据输入的有效元组的数量预分配数组大小
- Bitmaps
- 一些SIMD指令可以直接使用这些bitmap作为输入mask