前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Clickhouse一个查询是如何完成的?

Clickhouse一个查询是如何完成的?

原创
作者头像
felixxdu
发布2021-07-30 02:44:31
2.3K0
发布2021-07-30 02:44:31
举报
文章被收录于专栏:SQL引擎研究

Clickhouse SQL FUNCTION 介绍

Clickhouse中的函数大体可以分为三类:

  • 普通function 也可以称为 单行函数明细函数 ,由IFunction接口定义。对于被查询的表或者view每一行均返回一个结果值。常见的有数字运算函数,类型转化函数,条件函数,比较函数等。 查看clickhouse支持的明细函数多达600多个,并且随着版本迭代支持的数量还在增加中。如果需要增加支持新的函数,目前唯一的办法在source code中硬编码。目前还没有实现 create udf return type as ... 类似的udf的功能。可以通过以下SQL查询支持的function: select * from system.functions where "is_aggregate"=0select * from mysql('host:port','database', 'table', 'user','password')  --查看mysql数据库中的数据 select * from numbers() limit 10,1000000; --单线程生成10~1000010间的numbers select * from numbers_mt() limit 10,1000000; --多线程生成10~1000010间的numbers
  • 聚合function 由IAggregateFunction接口定义,对行集组(一组行的集合)进行聚合计算,聚合函数每组只能返回一个值。常见的有sum,avg函数等,聚合函数的状态支持序列化与反序列化,所以能够在分布式节点之间进行传输,以实现增量计算。查询支持的聚合function: select * from system.functions where "is_aggregate"=1
  • 表function 常见的有表function有 mysql url numbers remote 等,作为数据源(storage)使用,跟在 from 子句之后。常见用法:

全部的函数介绍见:官方文档

AST树的构造

Parser和Interpreter是非常重要的两组接口:Parser负责创建AST对象,Interpreter解释器则负责解释AST,并进一步创建查询的执行pipeline。它们与IStorage一起,串联起了整个数据查询的过程。

Parser将一条SQL语句以递归方法解析成AST语法树的形式。不同的SQL语句,会经由不同的Parser实现类解析。基于目前社区的master分支版本,parser的子类已经多达170多个。其中主要的是src/parser下,负责clickhouse类sql语法解析;mysql下的一些parser主要负责clickhouse可以作为mysql的客户端时的语法解析。

他们根据各自的职责实现了最主要的两个接口:getName()与parseImpl()。有负责解析DDL查询语句的ParserRenameQuery、ParserDropQuery 和ParserAlterQuery解析器,也有负责解析INSERT语句的 ParserInsertQuery解析器,还有负责SELECT语句的 ParserSelectWithUnionQuery等。

这个parser工作的方式是以层级展开,一个SQL语句过来,首先构造一个parserQuery的 根parser ,在根parser中先判断归属的大类别,然后大类别的parserImpl中将调用到多个二级类别的parser...以此类推等。

根/一级 parser(ParserQuery)中有以下二级parser(后面是功能注释)(ClickHouse/src/Parsers/ParserQuery.cpp):

代码语言:txt
复制
ParserQueryWithOutput query_with_output_p; //最常见的SQL语句都会匹配到这个parser
ParserInsertQuery insert_p(end); // insert 语句
ParserUseQuery use_p; // use db语句
ParserSetQuery set_p; // set key1 = value1语句
ParserSystemQuery system_p; // system 开头的语句 https://clickhouse.tech/docs/en/sql-reference/statements/grant/#grant-system
ParserCreateUserQuery create_user_p; // CREATE USER or ALTER USER
ParserCreateRoleQuery create_role_p; // CREATE ROLE or ALTER ROLE
ParserCreateQuotaQuery create_quota_p; // CREATE USER or ALTER USER
ParserCreateRowPolicyQuery create_row_policy_p; // 实现行级别的权限控制
ParserCreateSettingsProfileQuery create_settings_profile_p; // CREATE SETTINGS PROFILE or ALTER SETTINGS PROFILE
ParserDropAccessEntityQuery drop_access_entity_p; // DROP USER|ROLE | QUOTA
ParserGrantQuery grant_p; // GRANT or REVOKE 表和列级别的权限控制
ParserSetRoleQuery set_role_p; // SET ROLE
ParserExternalDDLQuery external_ddl_p; //EXTERNAL DDL FROM external_source(...) DROP|CREATE|RENAME

最主要的二级parser ParserQueryWithOutput又有以下子parser...

代码语言:txt
复制
ParserShowTablesQuery show_tables_p; // 负责show [tables /databases/...] 语法解析
ParserSelectWithUnionQuery select_p; // 负责select查询语句语法解析入口,内部有更多的parser
ParserTablePropertiesQuery table_p; // (EXISTS | SHOW CREATE) [TABLE|DICTIONARY] [db.]name [FORMAT format]
ParserDescribeTableQuery describe_table_p; // (DESCRIBE | DESC) ([TABLE] [db.]name | tableFunction) [FORMAT format]
ParserShowProcesslistQuery show_processlist_p; // SHOW PROCESSLIST
ParserCreateQuery create_p; // CREATE|ATTACH TABLE ...
ParserAlterQuery alter_p; // ALTER TABLE [db.]name
ParserRenameQuery rename_p; // RENAME TABLE [db.]name TO [db.]name, [db.]name TO [db.]name
ParserDropQuery drop_p; // DROP|DETACH|TRUNCATE TABLE [IF EXISTS] [db.]name
ParserCheckQuery check_p; // CHECK [TABLE] [database.]table
ParserOptimizeQuery optimize_p; // OPTIMIZE TABLE [db.]name [PARTITION partition] [FINAL] [DEDUPLICATE]
ParserKillQueryQuery kill_query_p; // KILL QUERY WHERE ... [SYNC|ASYNC|TEST]
ParserWatchQuery watch_p; // WATCH [db.]table EVENTS 功能介绍:https://clickhouse.tech/docs/en/sql-reference/statements/watch/
ParserShowAccessQuery show_access_p; // SHOW ACCESS
ParserShowAccessEntitiesQuery show_access_entities_p; // SHOW USERS; SHOW [CURRENT|ENABLED] ROLES; SHOW [SETTINGS] PROFILES 等
ParserShowCreateAccessEntityQuery show_create_access_entity_p; // SHOW CREATE USER [name | CURRENT_USER]
ParserShowGrantsQuery show_grants_p; // SHOW GRANTS [FOR user_name]
ParserShowPrivilegesQuery show_privileges_p; // SHOW PRIVILEGES
ParserExplainQuery explain_p; // EXPLAIN AST|PLAN|SYNTAX|PIPELINE SELECT...

以此类推。parser最后会生成一个Ast的语法树。它们有共同的接口IAST,继承体系和parser非常相似。

词法和语法解析

引入了两个概念:

Token: 代表若干个字符组成的一个有意义的”词“,token有很多type,见src/Parsers/Lexer.h下的宏定义。

Lexer:词法解析器,输入sql语句,吐出一个个token。最终将这些token加上一些有意义的信息按规则组织起来就是最终的Ast树。

AST树解析Function的过程

其中和function最相关的parser入口在ParserExpressionList,最终parse实现在ParserLambdaExpression中parseImpl。在parser阶段,不会检验function是否存在。首先会构建一个ASTIdentifier,然后结合参数一起构建起ASTFunction;在pipeline真正执行的时候才会校验参数的存在与否。

Interpreter到pipeline的执行

Interpreter解释器的作用就像Service服务层一样,聚合每个算子需要的资源并串联整个查询过程。 首先它会解析AST对象,然后执行“业务逻辑”(例如分支判断、设置 参数、调用接口等),最终返回IBlock对象,以线程的形式建立起一个查询执行pipeline。

一个 Query 处理流程大体是:

在clickhouse中,transformer就是算子的概念。所有 transformer 被编排成一个流水线(pipeline),然后交给 pipelineExecutor stream执行,每执行一个 transformer 中的一批数据集就会被加工并输出,一直到下游的 sinker。

Clickhouse实现了一系列基础 transformer 模块,见 src/Processors/Transforms,比如:

  • FilterTransform – WHERE 条件过滤
  • SortingTransform – ORDER BY 排序
  • LimitByTransform – LIMIT 裁剪
  • ExpressionTransform - 表达式执行

当我们执行:

SELECT age + 1 FROM t1 WHERE id=1 ORDER BY time DESC LIMIT 10 对于 ClickHouse 的 QueryPipeline 来说,它会按照以下方式进行编排组装:

代码语言:txt
复制
QueryPipeline::addSimpleTransform(Source)
QueryPipeline::addSimpleTransform(FilterTransform)
QueryPipeline::addSimpleTransform(SortingTransform)
QueryPipeline::addSimpleTransform(LimitByTransform)
QueryPipeline::addSimpleTransform(ExpressionTransform)
QueryPipeline::addSimpleTransform(Sinker)

当 QueryPipeline 进行 transformer 编排时,还需要进行更加底层的 DAG 连通构建。

代码语言:txt
复制
connect(Source.OutPort, FilterTransform.InPort)
connect(FilterTransform.OutPort, SortingTransform.InPort)
connect(SortingTransform.OutPort, LimitByTransform.InPort)
connect(LimitByTransform.OutPort, ExpressionTransform.InPort)
connect(ExpressionTransform.OutPort, Sinker.InPort)

这样就实现了数据的流向关系,一个 transformer 的 OutPort 对接另外一个的 InPort。同时,不同的transformer 的算子,如果可以并行执行(比如filter,expression就可以并行执行),会裂变出更多个 transformer ,达到一个并行加速的效果。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Clickhouse SQL FUNCTION 介绍
  • AST树的构造
    • 词法和语法解析
      • AST树解析Function的过程
      • Interpreter到pipeline的执行
      相关产品与服务
      数据库
      云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档