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"=0
select * 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 来说,它会按照以下方式进行编排组装:
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 ,达到一个并行加速的效果。