数据库查询引擎执行模型
火山模型(Volcano Model)
早期数据库受限于硬件水平,IO、内存和CPU资源都非常昂贵,所以大多数数据库的执行器都采用的是经典的Volcano 模型。
该计算模型将关系代数中每一种操作抽象为一个 Operator,将整个 SQL 构建成一个 Operator 树,从根节点到叶子结点自上而下地递归调用 next() 函数。
例如 SQL:
SELECT Id, Name, Age, (Age - 30) * 50 AS Bonus
FROM People
WHERE Age > 30
对应火山模型如下:
- User:客户端。负责获取用户的sql,也负责发送给客户端sql的执行结果。
- Project:垂直分割(投影),选择字段。对应于sql为:“SELECT Id, Name, Age, (Age - 30) * 50 AS Bonus”,接收子节点数据后,通过处理,得到需要返回给上层的结果值。
- Select(或 Filter):水平分割(选择),用于过滤行,也称为谓词。对应于sql为:“WHERE Age > 30”,接收子节点数据后,过滤掉不符合条件的数据。
- Scan:扫描数据。将数据从存储层拉到计算层。比如将People的表数据从磁盘拉到内存。对应sql为:“FROM People”
早期数据库受限于硬件水平,IO、内存和CPU资源都非常昂贵,比如计算层的数据一多,内存容易爆掉,所以火山模型采用每次只计算一行数据的方式,极大缩减了内存使用量。
火山模型的优点:简单易用,每个 Operator 可以单独抽象实现、不需要关心其他 Operator 的逻辑。
火山模型的缺点:查询树调用 next() 接口次数太多,并且一次只取一条数据,CPU 执行效率低;而 Joins, Subqueries, Order By 等操作经常会阻塞。
物化模型(Materialization Model)
物化模型的处理方式是:每个 operator 一次处理所有的输入,处理完之后将所有结果一次性输出。
物化模型更适合OLTP负载,这些查询每次只访问小规模的数据,只需要少量的函数调用次数。
物化模型每次处理全部的数据,虽然确实减少了大量函数调用开销,但是不可避免的会引起其他问题:
-
需要存储全部数据到内存中,很容易引起oom;
-
执行树的节点会强制转变成串行执行,多核下无法充分利用cpu。
向量化/批处理模型(Vectorized / Batch Model)
批处理模型是火山模型和物化模型的折衷。
向量化模型 和 火山模型 类似,每个 operator 需要实现一个 next() 函数,但是每次调用 next() 函数会返回一批的元组(tuples),而不是一个元组,所以向量化模型也可称为批处理模型。
算子每次执行的时候都会在内部攒一批数据,减少了每个 operator 的调用次数,数据大小尽可能和CPU cache对齐,不仅大大提高了cache命中率,而且有效了减少了函数调用次数。
参考
https://blog.csdn.net/qq_35423190/article/details/123129172