字节跳动基于 ClickHouse 优化实践之“查询优化器”
更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群
相信大家都对大名鼎鼎的 ClickHouse 有一定的了解了,它强大的数据分析性能让人印象深刻。但在字节大量生产使用中,发现了 ClickHouse 依然存在了一定的限制。例如:
缺少完整的 upsert 和 delete 操作
多表关联查询能力弱
集群规模较大时可用性下降(对字节尤其如此)
没有资源隔离能力
因此,我们决定将 ClickHouse 能力进行全方位加强,打造一款更强大的数据分析平台。本篇将详细介绍我们是如何构建ClickHouse的查询优化器。
查询优化器有多重要?
在传统的关系型数据库中,如Oracle、DB2、MySQL,查询优化器都是作为几个最重要的核心组件之一。可以说,没有查询优化器的数据库是不完整的。相对 OLTP 而言在OLAP领域中更是如此;对于分析类场景,查询更为复杂,计划好坏的差异更大。一个优秀的查询优化器可以防止用户写出不好的SQL导致执行速度慢,能够准确的选择出一条效率最高的执行路径,大幅度降低查询时间。相应的,一个不好的查询优化器,甚至会让查询变慢。
常见的优化器逻辑分为两类,一类叫“基于规则的优化(RBO)”,另一类称为“基于代价的优化(CBO)”,实际应用过程中应当两类兼顾才能取得最佳效果。
基于规则的优化
根据优化规则对关系表达式进行转换,这里的转换是说一个关系表达式经过优化规则后会变成另外一个关系表达式,同时原有表达式会被裁剪掉,经过一系列转换后生成最终的执行计划。RBO中包含了一套有着严格顺序的优化规则,同样一条SQL,无论读取的表中数据是怎么样的,最后生成的执行计划都是一样的。同时,在RBO中SQL写法的不同很有可能影响最终的执行计划,从而影响脚本性能。
基于代价的优化
根据优化规则对关系表达式进行转换,这里的转换是说一个关系表达式经过优化规则后会生成另外一个关系表达式,同时原有表达式也会保留,经过一系列转换后会生成多个执行计划,然后CBO会根据统计信息和代价模型(Cost Model)计算每个执行计划的Cost,从中挑选Cost最小的执行计划。
ByteHouse的查询优化器
目前主流的OLAP的引擎在查询优化器方面做的并不够好,尤其是ClickHouse。众所周知ClickHouse以快著称,但是它的快是采用了力大飞砖的方式,需要用户将数据预先生成大宽表,以避免过于复杂的多表查询从而获得高性能。而代价是,每次维度变化或新需求都需要大量操作,以及在必须使用多表关联进行分析的场景中显得十分无力。
作为一个企业级的OLAP数据库来说一个完善且强大的优化器是必不可少的,因此,ByteHouse从零开始自研的了查询优化器。
查询优化的完整流程
上图描述了整个查询的执行流程,从 SQL parse 到执行期间所有内容全部进行了重新实现(其中紫色模块),构建了一套完整的且规范的查询优化器。
主要功能模块
Analyzers
Analyzers 目录包括两部分功能:
一个是 QueryRewriter,一方面是通过 AST 改写的方式实现一些语法特性;我们同时支持 Clickhouse SQL 和标准 SQL,所以另一方面是确保在 Clickhouse SQL 模式下 SQL 语义能和原生 Interpreter 执行模式一致。
另一个是 QueryAnalyzer,用于对改写完的 AST 进行语义的分析和验证。Analyzer 区分 ANSI SQL 和 Clickhouse SQL 两种模式。
QueryRewriter 针对 ANSI SQL 的改写主要有:
With CTE/view 展开;
UDF 展开;
特定函数的改写,比如将 count(*) 改写为 count(),将 countDistinct(...) 改写为 uniqExact(...);
QueryRewriter 针对 Clickhouse SQL 的改写主要有:
With CTE/view 展开;
UDF 展开;
特定函数的改写;
JoinToSubquery 展开,对应于 Interpreter 链路下的 JoinToSubqueryTransformVisitor;
Qualified name 归一化,对应于 Interpreter 链路下的 TranslateQualifiedNamesVisitor;
Alias 改写,对应于 Interpreter 链路下的 QueryNormalizer;
QueryAnalyzer 查询语义进行分析和校验,将 AST 抽象成出结构化的数据结构,为下一步构建 plan 提供数据。在该模块中标准 SQL 和 Clickhouse SQL 进行了区分,一套代码同时兼容两种语义。
QueryPlan
在 Analyze 之后则是利用 Analyze 出的数据结构构建初始的查询计划。QueryPlan 是在社区的 QueryPlanStep 基础上改进而来,一方面增加了序列化/反序列化方法,为了计划下发执行基于 QueryPlan 并非 AST 或者 SQL 文本。另一方面是对社区中不合理的 Step 进行更改,让每个 Step 仅仅表达关系代数的语义而非很多执行相关的内容和参数,而这些执行相关的信息则是在每个执行的 server 上构建执行 pipeline 时才真正进行获得。
Optimizer
构建完执行计划后则是最为关键最后为核心的优化器模块。 PlanOptimizer 类是查询优化的入口类,首先会基于 PlanPattern 对 SQL的查询做一次粗粒度的分类,不同复杂度的查询使用不同的规则集合,提升效率。
优化器不管是 RBO 还是 CBO 本质上都是对查询做改写,只是改写的思路以及改写框架有不同的取舍。我们实现了三种改写框架,用于处理不同的场景:
基于 visitor 的改写框架:可以 Top-Down,也可以 Botton-Up 的 方式对一个 QueryPlan 做改写,它比较适合于带有上下文依赖的优化规则,例如 PredicatePushDown,需要把 Predicate 一层层的往下推。
基于 pattern-match 的改写框架:这种适合简单、通用的改写规则,例如对于两个连续的 Filter 做合并的动作,只要 QueryPlan 里面的 Sub Plan 符合 Filter-Filter 这样的 pattern,就可以 match 对应的优化规则,进行改写。
基于 Cascade 的改写框架:通过遍历等价计划,并将所有的等价计划存储在一个内存空间中,然后评估每种等价计划的代价,进而选择一种最优解。
查询优化器带来了什么
在性能方面,原生Clickhouse受限于缺少查询优化器,对于 TPC-DS测试集的99个SQL用例仅能正常运行很少一部分查询,即使通过手动改写 SQL 也仅能成功运行 80%的查询。在实现了完善的优化器之后可以直接运行全部 TPC-DS 原始 SQL,改进后的 Clickhouse 才这正可以算是可用的 OLAP 数据库。不仅仅是可以正常执行这些复杂查询,而且效率也得到了很大的提升,相对在没优化器的情况下手动改写的 SQL ,性能提升 6 倍以上。在内部的一些业务场景中性能也有近10倍的提升。
优化器的能力方面:
RBO:支持:列裁剪、分区裁剪、表达式简化、子查询解关联、谓词下推、冗余算子消除、Outer-JOIN 转 INNER-JOIN、算子下推存储、分布式算子拆分等常见的启发式优化能力。
CBO:基于 Cascade 搜索框架,实现了高效的 Join 枚举算法,以及基于 Histogram 的代价估算,对 10 表全连接级别规模的 Join Reorder 问题,能够全量枚举并寻求最优解,同时针对大于10表规模的 Join Reorder 支持启发式枚举并寻求最优解。CBO 支持基于规则扩展搜索空间,除了常见的 Join Reorder 问题以外,还支持 Outer-Join/Join Reorder,Magic Set Placement 等相关优化能力。
分布式计划优化:面向分布式MPP数据库,生成分布式查询计划,并且和 CBO 结合在一起。相对业界主流实现:分为两个阶段,首先寻求最优的单机版计划,然后将其分布式化。我们的方案则是将这两个阶段融合在一起,在整个 CBO 寻求最优解的过程中,会结合分布式计划的诉求,从代价的角度选择最优的分布式计划。对于 Join/Aggregate 的还支持 Partition 属性展开。
高阶优化能力:实现了 Dynamic Filter pushdown、单表物化视图改写、基于代价的 CTE (公共表达式共享)。
下面我们用TPC-DS标准测试集,来为大家展现一下添加优化器前后的差别:
在没有优化器时,仅能完成26个SQL的查询。而添加了优化器后,能够完整跑完TPC-DS的全部99个SQL,并且在此前能完成的查询中,性能也得到了极大的提升。
字节跳动基于 ClickHouse 优化实践之“查询优化器”的更多相关文章
- 字节跳动基于ClickHouse优化实践之“多表关联查询”
更多技术交流.求职机会.试用福利,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 相信大家都对大名鼎鼎的ClickHouse有一定的了解了,它强大的数据分析性能让人印象深刻.但在字节大量 ...
- 字节跳动基于Apache Hudi构建EB级数据湖实践
来自字节跳动的管梓越同学一篇关于Apache Hudi在字节跳动推荐系统中EB级数据量实践的分享. 接下来将分为场景需求.设计选型.功能支持.性能调优.未来展望五部分介绍Hudi在字节跳动推荐系统中的 ...
- 字节跳动数据平台技术揭秘:基于 ClickHouse 的复杂查询实现与优化
更多技术交流.求职机会.试用福利,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 ClickHouse 作为目前业内主流的列式存储数据库(DBMS)之一,拥有着同类型 DBMS 难以企及 ...
- 字节跳动流式数据集成基于Flink Checkpoint两阶段提交的实践和优化
背景 字节跳动开发套件数据集成团队(DTS ,Data Transmission Service)在字节跳动内基于 Flink 实现了流批一体的数据集成服务.其中一个典型场景是 Kafka/ByteM ...
- SQL Server查询优化器的工作原理
SQL Server的查询优化器是一个基于成本的优化器.它为一个给定的查询分析出很多的候选的查询计划,并且估算每个候选计划的成本,从而选择一个成本最低的计划进行执行.实际上,因为查询优化器不可能对每一 ...
- mysql查询优化之二:查询优化器的局限性
在<mysql查询优化之一:mysql查询优化常用方式>一文中列出了一些优化器常用的优化手段.查询优化器在提供这些特性的同时,也存在一定的局限性,这些局限性往往会随着MySQL版本的升级而 ...
- SQL Server 查询优化器运行方式
一.结合实际,谈索引使用的误区 理论的目的是应用.虽然我们刚才列出了何时应使用聚集索引或非聚集索引,但在实践中以上规则却很容易被忽视或不能根据实际情况进行综合分析.下面我们将根据在实践中遇到的实际问题 ...
- [译]SQL Server 之 查询优化器
因为生成查询计划的代价比较大,所以查询计划将会被缓存. 树形结构 SQL 查询首先被转化为树形结构,每个节点都是一个查询操作.例如: SELECT * FROM Customers C INNER J ...
- Presto 在字节跳动的内部实践与优化
在字节跳动内部,Presto 主要支撑了 Ad-hoc 查询.BI 可视化分析.近实时查询分析等场景,日查询量接近 100 万条.本文是字节跳动数据平台 Presto 团队-软件工程师常鹏飞在 Pre ...
- Go RPC 框架 KiteX 性能优化实践 原创 基础架构团队 字节跳动技术团队 2021-01-18
Go RPC 框架 KiteX 性能优化实践 原创 基础架构团队 字节跳动技术团队 2021-01-18
随机推荐
- Web Woeker和Shared Worker的使用以及案例
目录 1.前言 2.介绍 Web Worker 3.使用须知及兼容性 3.1.使用须知 3.2.兼容性 4.使用 Web Worker 4.1.创建 Web Worker 4.2.与主线程通信 4.3 ...
- [WPF]浅析资源引用(pack URI)
WPF中我们引用资源时常常提到一个概念:pack URI,这是WPF标识和引用资源最常见的方式,但不是唯一的方式.本文将介绍WPF中引用资源的几种方式,并回顾一下pack URI标识引用在不同位置的资 ...
- linux系统centos7安装docker
1.Docker官网安装地址 https://docs.docker.com/engine/install/centos/#prerequisites 2.离线安装下载地址 https://downl ...
- CSS 也能实现 if 判断?实现动态高度下的不同样式展现
最近在群里,有个小伙伴问了这么一道很有趣的问题: CSS 能否实现,容器再某个高度下是某种表现,一旦超出某个高度,则额外展示另外一些内容 为了简化实际效果,我们看这么一张示意效果图: 可以看到,当容器 ...
- 万字长文:从 C# 入门学会 RabbitMQ 消息队列编程
RabbitMQ 教程 目录 RabbitMQ 教程 RabbitMQ 简介 安装与配置 安装 RabbitMQ 发布与订阅模型 生产者.消费者.交换器.队列 多工作队列 交换器类型 Direct F ...
- P5318 查阅文献
题意大概意思就是分别用dfs与bfs遍历一个图,特殊要求是从编号小的点开始遍历. 用邻接表存图,至今我也没想明白怎么才可以从编号小的点开始遍历,明白是排序,但是不知道如何排序,题解中的排序方法是:按照 ...
- Net 高级调试之十:轻量级代码生成的调试
一.简介 今天是<Net 高级调试>的第十篇文章.说起来,高级调试,调试的内容还是挺多的,技巧也不少,但是,要想做一个合格的高级调试人员,还需要掌握如何调试动态生成的IL代码.今天要探讨的 ...
- 【Javaweb】servlet七 | 解决post请求中文乱码问题
问题描述 在get请求时(可以接收) post请求时(出现了中文乱码问题) 解决方案 在doPost函数中添加如下代码 // 设置请求体字符为UTF-8,从而解决post请求的中文乱码问题// 也要在 ...
- ZooKeeper论文阅读笔记
ZooKeeper论文传送门 介绍 ZooKeeper 是一个开源的分布式协调服务,它提供了高可用性和一致性的数据管理和协调功能.它被设计用于构建可靠的分布式系统,并提供了一组简单而强大的 wait- ...
- Alist手动安装并使用教程
一.官方文档及下载地址 1.官方文档 AList文档 2.下载地址 alist · GitHub 二.下载并解压文件 以Windows为例,下载指定版本的文件. 三.运行 1.解压文件并进入文件夹: ...