基于Impala的高性能数仓实践之执行引擎模块

导读:

本系列文章将结合实际开发和使用经验,聊聊可以从哪些方面对数仓查询引擎进行优化。

Impala是Cloudera开发和开源的数仓查询引擎,以性能优秀著称。除了Apache Impala开源项目,业界知名的Apache Doris和StarRocks、SelectDB项目也跟Impala有千丝万缕的联系。笔者所在的网易数帆大数据团队,是最早一批将其作为分析型数仓查询引擎的团队,目前正基于Impala打造有数高性能数仓引擎。

文章大致可以分为这几个部分:首先会对简单介绍下Impala的架构和元数据管理,以便后续内容展开;接着从执行引擎,存储优化,物化视图,数据缓存和虚拟数仓等维度进行探讨。本文为执行引擎篇。

1

Impala简介

Impala集群包含一个Catalog Server (Catalogd)、一个Statestore Server (Statestored) 和若干个Impala Daemon (Impalad)。Catalogd主要负责元数据的获取和DDL的执行,Statestored主要负责消息/元数据的广播,Impalad主要负责查询的接收和执行。

基于Impala的高性能数仓实践之执行引擎模块

Impalad又可配置为coordinator only、 executor only 或coordinator and executor(默认)三种模式。Coordinator角色的Impalad负责查询的接收、计划生成、查询的调度等,Executor角色的Impalad负责数据的读取和计算。默认配置下每个Impalad既是Coordinator又是Executor。生产环境建议做好角色分离,即每个Impalad要么是Coordinator要么是Executor。

1.1 元数据管理

Impala的元数据缓存在catalogd和各个Coordinator角色的Impalad中。Catalogd中的缓存是最新的,各个Coordinator都缓存的是Catalogd内元数据的一个复本。元数据由Catalogd向外部系统获取,并通过Statestored 传播给各个Coordinator。

以Hive表为例,Catalogd中的元数据分别从Hive Metastore(HMS)和HDFS NameNode(NN)获取。从HMS获取的信息包括元数据信息和统计信息两部分,元数据信息指有哪些库和表,表定义,列类型等,对应“show databases,show tables,show create table xxx,show ”等操作。统计信息包括表的大小,行数,分区和各列的信息等,对应“show table stats xx,show column stats xx”等操作。从NN获取的是文件粒度的信息,包括文件存储位置,副本和文件块信息等。

1.2 管理服务器

管理服务器是有数高性能数仓增加的Impala模块,提供集群粒度的SQL查看界面,持久化保存历史查询信息并展示,SQL审计,查询错误和查询性能分析,自动进行统计信息计算等。

基于Impala的高性能数仓实践之执行引擎模块

2

执行引擎(Execute Engine)

2.1 执行模型

在执行模型这块,目前主要有动态代码生成(code generation或just in time/JIT)和向量化计算两个流派,Impala主要是基于JIT进行性能优化,对于向量化引擎,Impala社区版目前并没有相关规划,有数高性能数仓团队也有计划对其进行向量化改造。

在具体实现上,Impala属于改进版的火山模型,官方论文描述为

即在传统的火山模型的基础上加入Exchange操作符,用于进行不同执行节点的数据交换。每次会获取一批记录而不是一条记录。

不管是JIT还是矢量化,其目的都是尽可能地减少执行引擎核心代码流程的调用次数并提高函数执行效率,这对于需要处理海量记录时非常重要。Impala通过每次获取一批记录来减少调用次数,再利用JIT技术来生成针对特定类型数据的执行流程函数,提高每次调用的效率。

更进一步,Impala采用数据流水线(streaming pipelined)执行机制,充分利用计算资源进行并发执行。在Impala 4.0版本,完整支持了executor节点的多线程执行模型,进一步提高并发能力,压榨计算资源。

动态代码生成原理及优化

JIT技术与静态编译技术相反,其是在具体的查询运行之前才进行代码编译,此时,查询中需要处理的列类型,用到的算子和函数都已经确定,可以为该查询生成特定版本的处理函数。如下图所示:

基于Impala的高性能数仓实践之执行引擎模块

左侧是通用的从文件读取记录(tuple)并解析的行数,外层一个for循环用于对每一列进行处理,内层的switch用于判断列的类型并调用特定的解析函数。如果我们已经知道该记录由三列组成,类型分别为int,bool和int,那么JIT技术就可以生成如图右侧的函数版本,不需要for循环,也不需要switch判断,显然,执行效率更高。

总的来说,Impala使用LLVM来进行JIT优化,生成对于某个具体查询最优的函数实现。其优化项具体包括移除条件分支(Removing conditionals,如上所示)、移除内存加载和内联虚函数调用等。

启用动态代码生成时,在查询执行前需要先动态生成其执行代码,因此有一定的时间消耗,对于小查询,动态代码生成可能是有害的,生成代码的时间都有可能超过SQL执行时间。Impala提供了DISABLE_CODEGEN_ROWS_THRESHOLD参数,默认为50000,如果SQL需要处理的记录数小于该值,则不会使用动态代码生成进行执行优化。Impala 4.0版本对JIT进行了进一步优化,采用异步化改造来避免生成JIT代码对查询性能的影响,当编译未完成时使用原函数,完成后无缝切换成优化后的函数代码。

2.2 计算资源

Impala属于SQL on Hadoop的一种,基于MPP(Massively Parallel Processing,即大规模并行处理)架构,正常情况下,查询涉及的各种操作均在内存中完成的,因此,可用内存的多少及对其的利用效率,对Impala查询性能有极大影响。同样地,作为一个OLAP查询引擎,可用的CPU资源对查询性能也至关重要。Impala虽提供了少数CPU相关配置项,如num_threads_per_core 等,但对CPU使用的控制能力较差。本小节后续仅介绍内存资源相关,CPU计算后续另开一篇单独介绍。

Impala资源池

Impala有比较丰富的资源使用限制方式,称为准入控制。其中资源池(resource pool)是Impala进行并发控制的主要手段,可以决定某个查询是否会被拒绝,或执行,或排队。其主要有两种控制方式,一种是手动设置最大并发数控制,超过阈值的请求会进行排队,可以设置允许排队的最大请求数和排队时长,超过阈值的请求直接返回失败;另一种是基于内存的并发控制,下面进行重点介绍。

基于内存的并发控制

Impala集群支持通过fair-scheduler.xml设置多个资源池并规定其最大可用内存(maxResources),再通过llama-site.xml为每个资源池设置请求级别的内存限制,包括内存分配上下限max-query-mem-limit和min-query-mem-limit,及clamp-mem-limit-query-option。除了通过资源池相关配置控制请求的内存使用,还可以通过MEM_LIMIT请求选项设置内存限制。而clamp-mem-limit-query-option就是设置是否允许MEM_LIMIT设置的内存突破资源池内存配置的限制。

需要注意的是,max-query-mem-limit,min-query-mem-limit和MEM_LIMIT设置的是请求在每个executor节点允许申请的最大内存,请求申请的总内存还需要乘上执行该请求的executor节点个数。

若Impala通过预估发现查询所需的内存资源超过集群总内存资源,该查询会被拒绝;若总资源满足,但由于部分资源已被其他查询占用,则会将其放入请求队列,待可用资源满足查询要求时再按查询提交的先后顺序调度执行。

若预估的内存资源超过了设置的max-query-mem-limit,则以max-query-mem-limit为准,若小于min-query-mem-limit,则以min-query-mem-limit为准。假设查询请求设置了MEM_LIMIT,需先判断clamp-mem-limit-query-option的值,若为true,则仍然受max-query-mem-limit,min-query-mem-limit约束。下面举个例子进行说明:

假设clamp-mem-limit-query-option为true,则该资源池最多只能同时执行2个查询A这样的请求(2 * 5 * 10GB)。

通过上面的例子可知Impala的准入控制会在每个executor为查询请求预留所需的内存,因此,所预留的内存应该尽可能接近实际所需内存,预留过少会导致查询失败或中间结果溢出,预留过多会导致集群资源没有被充分利用。在内存资源管理的精确性方面,Impala还有较多需优化的点。

准入控制存在的问题

(1)集群同步

Impala进行准入控制的载体是coordinator节点,由于一个集群至少有2个及以上的coordinator节点,但准入控制是针对整个集群的。Impala通过statestore的impala-request-queue topic机制在coordinator间周期性地同步每个coordinator上的查询并发和内存使用情况。

Impala采用去中心化的设计来实现准入控制,而不是通过一个中心节点来统一决策,虽然在性能和可用性上有优势,但是这会导致coordinator获取的其他coordinator信息过旧的问题,尤其是在查询并发度较高时,会导致准入控制模块做出错误的决策。

(2)内存预估精度

Impala需要基于统计信息来评估查询需要消耗多少内存,因为统计信息里面会记录表的记录数,列的类型和大小等。没有统计信息,就无法正确评估内存消耗,也就无法以较优的方式执行该查询。(统计信息相关的详细描述见下一小节)

但就算是有统计信息,仍有可能依然没法正确估算需消耗的内存量。如下所示:

基于Impala的高性能数仓实践之执行引擎模块

上图第一张的”Mem Usage”和”Mem Estimate”分别表示查询实际消耗和预估消耗的总内存,可见明显差别。上图下面两张为通过compute incremental stats/compute stats前后通过explain看到的内存预估情况,可见每个节点均22MB(共67个executor节点),即该查询内存预估不精确不是因为没有统计信息导致的。

数据溢出(spill to disk)

内存不够怎么办?

如果因为集群同步延迟或内存预估低于实际所需内存,导致查询执行过程中消耗的内存超过准入控制的计算值,此时数据溢出功能可以派上用场。数据溢出是Impala一种兜底机制,避免因中间结果集过大导致内存不足,进而引起查询失败。当然,并不是所有情况的内存不足都会启用数据溢出,能够进行数据溢出的算子主要包括group by,order by,join,distinct和union;

数据溢出机制的用处在于,能够最大限度避免查询失败。OLAP场景由于SQL复杂度远高于OLTP,耗时也明显更长,查询失败的代价更大。其带来的问题是因为需要将中间结果写盘并读取,SQL查询性能会明显下降,因此,应该通过查询优化尽可能避免数据溢出。

关闭数据溢出

有两种方法可以关闭数据溢出,均是通过query option来设置,分别是SCRATCH_LIMIT和DISABLE_UNSAFE_SPILLS。

SCRATCH_LIMIT用于设置溢出目录的大小,当设为0时,即关闭了数据溢出特性。

DISABLE_UNSAFE_SPILLS更加智能,用于禁止不安全的数据溢出。Impala认为下列情况属于不安全的溢出:查询中存在没有统计信息的表,或没有为join设置hint,或对分区表进行insert … select操作。

优化资源分配效率

(1)集中式准入控制

从Impala社区了解到,目前Impala在开发新的准入控制实现,预计后续会提供集中式的准入控制方案,详见 Single Admission Controller per Cluster;

(2)降低准入信息同步延时

虽可以通过statestore_update_frequency_ms缩短topic更新周期来缓解,但无法从根本上解决。除此之外,在Impala部署时,还应该控制coordinator的数量,对于50个节点以下的集群,一般情况下配置2个coordinator实现高可用即可;

(3)丰富统计信息类型

至于为什么在有统计信息情况下预估还是不够精确,原因也很好理解,即统计信息本身过于粗粒度,缺乏像直方图这样细粒度的数据统计。

基于历史查询的内存估算优化(HBO)

从前述的例子可知,有数的Impala版本通过管理服务器保存了Impala执行过的历史查询信息,其中就包括了查询的实际内存使用量。在BI场景,报表SQL会重复执行,往往一天一次或数次,完全可以将该SQL第一次执行的内存使用量作为后面几次的内存预估值。进一步,可以提取同类SQL查询模板,计算该模板下SQL的最大及平均内存使用量作为内存预估值。

此外,由于BI报表的SQL都来源于事先创建的数据模型,可以预先计算数据模型SQL的内存消耗,在执行该模型对应的报表SQL时,模型部分的内存消耗无需再次计算,直接代入即可。基于此,我们完成了方案设计和功能实现,下图为一个查询开启HBO优化前后的内存估算值变化

基于Impala的高性能数仓实践之执行引擎模块

下图为将HBO用在某业务集群上启用前后的效果对比。

基于Impala的高性能数仓实践之执行引擎模块
基于Impala的高性能数仓实践之执行引擎模块

2.3 基于代价优化(CBO)

CBO与RBO(基于规则优化)都是传统的执行计划优化方式。CBO主要基于索引和统计信息等元数据来选择更优的执行计划。传统的商业数仓和OLTP系统有健全的索引系统,并且会自动计算表的统计信息。因此,CBO往往能够较充分发挥。但目前开源的分析型数仓查询引擎(下称OLAP),做得并不好,以Impala为例,自身并没有索引系统,主要依赖底层的存储系统,虽提供了统计信息计算的命令,但不会自动进行统计信息计算。在此,我们先介绍其对统计信息的使用。

统计信息的用途

在Impala中,统计信息主要用于准入控制和确定Join方式等场景。

确定Join方式包括Join的先后顺序和Join的方法,Join方式有shuffle和broadcast两种。如下文描述:

三个及以上的表进行Join时,一般选择将结果集最小的Join先算掉,对于两表Join,若是大表和小表,由于Impala使用Hash Join,采用大表左(probe table),小表在右(build table)的方式,将小表broadcast到大表分片所在的各个executor节点,若是大表跟大表,则采用shuffle的方式,两表都会进行Hash分片,各个executor节点对两表相同Hash值的分片进行Join。

如果SQL中的表缺失了统计信息,如查询所涉及的记录数,所涉及的各列的大小等,则无法准确预估该SQL的内存消耗,导致准入控制模块出现误判,生产环境中常会出现因executor节点可用内存不足导致查询排队的情况,但其实此时内存是够的,这里有多方面的原因,比如该查询SQL所需内存预估值过大,或已经在执行的查询的配额过大等。相反的,如果预估所需内存过小,则可能导致查询在执行过程中因为executor节点无法分配所需内存而导致SQL执行失败。

同样的,如果没有统计信息,也就无法判断两表参与Join的记录数和大小,出现大小表Join时大表被广播的情况。在Impala中,两表Join,没有统计信息的表会被放在右边,所以,对大表做统计信息计算显得更加重要。

除此之外,统计信息用于调优前文提到的动态代码生成。上文提到的DISABLE_CODEGEN_ROWS_THRESHOLD参数需要在有统计信息的情况下使用,无统计信息,意味着不知道需要处理多少条记录,该参数也就无法生效。

统计信息计算

Impala为什么不像MySQL等数据库一样自动计算和更新表统计信息呢?个人认为,主要是不好做,MySQL自动进行统计信息更新的方式是监测表中的记录,如果更新的记录数超过设定的阈值,则自动触发更新。当Impala对接Hive表时,往往仅用于查询而不是数据产出,数据产出由Spark或Hive负责,因此也就无法自动感知表中数据的变化。

如果能够及时感知Hive表的数据变化情况,那么就有办法驱动统计信息更新。Impala可以通过订阅有数大数据开发及管理平台的数据产出日志,感知Hive表的数据变化。具体的统计信息计算由Impala管理服务器执行。Impala 3.4版本下,表和列的统计信息字段如下所示。

代码语言:javascript代码运行次数:0运行复制

[localhost:21000] > show table stats t1;Query: show table stats t1+-------+--------+------+--------+| #Rows | #Files | Size | Format |+-------+--------+------+--------+| -1    | 1      | 33B  | TEXT   |+-------+--------+------+--------+Returned 1 row(s) in 0.02s[localhost:21000] > show column stats t1;Query: show column stats t1+--------+--------+------------------+--------+----------+----------+| Column | Type   | #Distinct Values | #Nulls | Max Size | Avg Size |+--------+--------+------------------+--------+----------+----------+| id     | INT    | -1               | -1     | 4        | 4        || s      | STRING | -1               | -1     | -1       | -1       |+--------+--------+------------------+--------+----------+----------+Returned 2 row(s) in 1.71s

进行统计信息计算的“compute stats”命令本质是通过两条SQL分别获取表/分区和列粒度的信息:即为上述两个查询结果中的为“-1”的字段进行赋值,如下所示:

基于Impala的高性能数仓实践之执行引擎模块

两个SQL均需在全表扫描的基础上进行聚合操作。对于大表,这需要消耗可观的计算资源,而且,若表中的列个数非常多,则统计信息的存储空间也是需要考虑的因素(需要持久化到HMS元数据库中,并缓存在catalogd和impalad)。对于分区表,一般使用“compute incremental stats”每次仅计算一个分区,但有时仍会因为统计信息过大而出错,这是由于超过了增量统计信息计算的“inc_stats_size_limit_bytes”参数设定值导致:

代码语言:javascript代码运行次数:0运行复制

org.apache.impala.common.AnalysisException: Incremental stats size estimate exceeds 200.00MB.

参考Impala的文档,统计信息计算可以进行如下优化:

对于分区表,仅对频繁查询的分区计算统计信息,并定期删除旧分区统计信息;对于宽表,仅对频繁查询的列计算统计信息;对于记录数过多的表,启用统计信息高级特性:推断和采样(Extrapolation and Sampling)

从性能优化角度,统计信息显然是越精细越好。但在OLAP这种大数据量场景下,越精细意味着越庞大的统计信息计算和存储开销,使用何种粒度的统计信息是个需要权衡的问题。

2.4 查询的分布式执行

在大数据场景下,单靠单台服务器执行分析型查询操作显然过于单薄,所以分析型数仓一般基于MPP(Massively Parallel Processing,即大规模并行处理)架构,Impala就是基于MPP,可以将一个查询分为多个片段分布式执行。在Impala上,分布式执行又可分为节点间和节点内。

为了能够在分布式执行的同时,能够对不同业务或不同类型的SQL进行隔离,避免相互影响,有数的Impala版本进一步引入了虚拟数仓概念,能够有效的进行资源隔离,同时有兼顾资源的有效利用。对于虚拟数仓,我们会在后续单独写一篇文章进行介绍。

节点间并行

在“Impala简介”小节提到,Impala有多个executor节点,在确定执行计划时,Impala会充分考虑并发执行该查询,尽可能将需要扫描的数据分成range分发到各executor节点上执行,并响应对数据进行查询所需的算子进行分布式计算。

因此,在数据量足够大的情况下,增加executor节点数可以提升查询性能。若executor所在服务器的计算资源充足,可以考虑同一台服务器上部署多个executor节点。

节点内并行

Impala还可以通过MT_DOP参数配置查询在executor节点内的执行并发线程数。对于统计信息计算产生的SQL,Impala自动将MT_DOP设置为4以提升计算性能。相比节点间并行,节点内并行通过query option设置,更加灵活可控。在Impala 3.4及之前版本,MT_DOP不够完善,无法支持分布式Join等操作,从Impala 4.0开始,MT_DOP已支持绝大部分算子。我们在TPCH和TPCDS场景下的测试数据表明,将MT_DOP设置为16的性能明显好于不设置或将其设置为1时的性能,绝对性能有数倍提升。

合理配置并行数

显然,查询的执行并行度不是越高越好,需要考虑Impala集群的查询并发数以及executor节点的计算资源可用量。一般建议executor节点所在服务器的计算资源和网络资源的利用率应该小于80%。

对于节点内并行,需要考虑impala profile输出对性能的影响,在配置高MT_DOP时,应启用精简模式的profile-v2(gen_experimental_profile=true),防止profile过大。

2.5 查询重试和改写

查询重试

查询出错的原因有很多,比如执行该查询的任意一个executor不可用(宕机或网络隔离等),或因排队过久导致执行超时,或因元数据过旧导致执行出错等。

在Impala 4.0版本,引入了查询透明重试的特性,该特性会判断引起查询出错的原因,目前支持对因executor不可用而出错的查询进行自动重试,无需用户/客户端参与。

元数据过旧重试

因元数据过旧导致执行出错是Impala特有的错误场景,最典型的错误形如:“Failed to open HDFS file …..”。有数的Impala版本还支持对该类错误进行透明重试,coordinator节点通过匹配错误关键字识别错误类型。在重试前会解析HDFS文件路径获取库名和表名,并获取当前该表的元数据版本,重试时若元数据版本未变化,这会将对应的表元数据失效掉,重新加载元数据。

对元数据错误进行查询重试,是一种把错误内部化的一种优化方式。元数据过旧是由于Impala出于性能考虑对其进行了缓存,对用户来说元数据缓存应该是黑盒的,因缓存过旧导致的错误,不应该直接暴露给使用者,应该在系统设计时消化掉。

SQL改写

常规改写

Impala提供了表达式级别的改写优化,改写规则主要包括常量折叠、通用表达式提取和,全部规则如下所示:

代码语言:javascript代码运行次数:0运行复制

List rules = new ArrayList();      // BetweenPredicates must be rewritten to be executable. Other non-essential      // expr rewrites can be disabled via a query option. When rewrites are enabled      // BetweenPredicates should be rewritten first to help trigger other rules.      rules.add(BetweenToCompoundRule.INSTANCE);      //between转大小比较      // Binary predicates must be rewritten to a canonical form for both Kudu predicate      // pushdown and Parquet row group pruning based on min/max statistics.      rules.add(NormalizeBinaryPredicatesRule.INSTANCE);      //规范化二元谓语,如“5 + 3 = id"改为"id = 5 + 3"      if (queryCtx.getClient_request().getQuery_options().enable_expr_rewrites) {        rules.add(FoldConstantsRule.INSTANCE);        //常量折叠,如"1 + 1"改为"2"        rules.add(NormalizeExprsRule.INSTANCE);        //规范化表达式,如"id = 0 OR false"改为"FALSE OR id = 0"        rules.add(ExtractCommonConjunctRule.INSTANCE);        //通用表达式提取,如"(int_col         // Relies on FoldConstantsRule and NormalizeExprsRule.        rules.add(SimplifyConditionalsRule.INSTANCE);        //简化条件判断,场景覆盖较广,包括if、case等等,如"if(true, id, id+1)"改为"id"        rules.add(EqualityDisjunctsToInRule.INSTANCE);        //or转in,如"int_col = 1 or int_col = 2"改为"int_col IN (1, 2)"        rules.add(NormalizeCountStarRule.INSTANCE);        //count(常量)转为count(*),如"count(1)"改为"count(*)"        rules.add(SimplifyDistinctFromRule.INSTANCE);        //简化条件判断(is distinct, , 等)语句,如"if(bool_col  bool_col, 1, 2)"改为"1"        rules.add(SimplifyCastStringToTimestamp.INSTANCE);        //简化将字符串转为时间戳,如"cast(unix_timestamp(date_string_col) as timestamp)"改为"CAST(date_string_col AS TIMESTAMP)"      }      exprRewriter_ = new ExprRewriter(rules);    }

从上面的代码可知,大部分的改写规则需要通过ENABLE_EXPR_REWRITES 这个query option开启。

定制改写

有数的Impala版本在上述基础上,结合BI工具和业务属性进行针对性的优化,有助于提升BI查询性能。其中一项优化是简化时间比较表达式。举例如下:

代码语言:javascript代码运行次数:0运行复制

SELECT TO_DATE(CAST(t1.dt AS TIMESTAMP)) d0,t2.itemname d1,COUNT(DISTINCT t1.user_id) m0FROM music_dws.dws_log_music_xxx_aggr_di t1WHERE (((TO_DATE(CAST(t1.dt AS TIMESTAMP)) >= CAST('2021-01-01' AS TIMESTAMP)) AND (TO_DATE(CAST(t1.dt AS TIMESTAMP)) 

已知t1表为按天分区,dt为分区字段,结构为’yyyy-mm-dd’,那么在此条件下,可以将dt字段与时间字符串进行比较,去掉CAST AS TIMESTAMP和TO_DATE操作,上述SQL可改写为:

代码语言:javascript代码运行次数:0运行复制

SELECT t1.dt d0, t2.itemname d1,COUNT(DISTINCT t1.user_id) m0FROM music_dws.dws_log_music_xxx_aggr_di t1WHERE (t1.dt >= '2021-01-01') AND (t1.dt 

高级改写

从上面Impala原生支持的改写规则可以看出,其支持的改写规则都比较初级,实现上是将SQL拆解为SelectList、FromClause、WhereClause、GroupByExpr和OrderByExpr等片段后,对各片段进行改写。并没有对SQL进行整体的,跨片段的改写。

有数的Impala版本还可进一步对SQL整体进行改写优化,其中最为重要的是基于物化视图的SQL透明改写,我们会在后续单独写一篇文章进行介绍。除了物化视图改写,还有其他一些优化手段,如左连接(left join)消除等。

左连接消除

一般来说,BI软件基于某个数仓模型(宽表,星型,雪花型等)创建报告,其中包括一张或多张报表,举一个网易云音乐使用有数BI报表模型为例,SQL形如:

代码语言:javascript代码运行次数:0运行复制

SELECT t1.os, other select listFROM music_impala.left_join_table1 t1LEFT JOIN music_impala.left_join_table2 t2 ON ((t1.is_new = t2.is_new) AND (t1.anchor_id = t2.anchor_id) AND (t1.app_ver = t2.app_ver) AND (t1.os = t2.os) AND (TO_DATE(CAST(t1.dt AS TIMESTAMP)) = t2.report_date))LEFT JOIN music_impala.left_join_table3 t3 ON ((t1.is_new = t3.is_new) AND (t1.anchor_id = t3.anchor_id) AND (t1.app_ver = t3.app_ver) AND (t1.os = t3.os) AND (TO_DATE(CAST(t1.dt AS TIMESTAMP)) = t3.report_date))LEFT JOIN music_iplay.left_join_table4 t4 ON ((t1.dt = t4.dt) AND (t1.anchor_id = CAST(t4.anchor_id AS VARCHAR(255))))

可以认为,该模型是将下面这4个数仓表通过左连接打宽成一个逻辑大宽表。

代码语言:javascript代码运行次数:0运行复制

music_impala.left_join_table1、music_impala.left_join_table2、music_impala.left_join_table3music_impala.left_join_table4`

下面是产生的一个报表的列表筛选器组件产生的SQL。

代码语言:javascript代码运行次数:0运行复制

SELECT t1.os d0FROM music_impala.left_join_table1 t1LEFT JOIN music_impala.left_join_table2 t2 ON ((t1.is_new = t2.is_new) AND (t1.anchor_id = t2.anchor_id) AND (t1.app_ver = t2.app_ver) AND (t1.os = t2.os) AND (TO_DATE(CAST(t1.dt AS TIMESTAMP)) = t2.report_date))LEFT JOIN music_impala.left_join_table3 t3 ON ((t1.is_new = t3.is_new) AND (t1.anchor_id = t3.anchor_id) AND (t1.app_ver = t3.app_ver) AND (t1.os = t3.os) AND (TO_DATE(CAST(t1.dt AS TIMESTAMP)) = t3.report_date))LEFT JOIN music_iplay.left_join_table4 t4 ON ((t1.dt = t4.dt) AND (t1.anchor_id = CAST(t4.anchor_id AS VARCHAR(255))))GROUP BY t1.osLIMIT 20000

对于BI软件来说,基于模型产生该SQL非常合理。但考虑到模型是逻辑的大宽表,在Impala层面,可以对SQL进行改写以优化查询性能。

该筛选器用于在报告中对music_impala.left_join_table1的os字段进行选择,且模型中各表Join的条件(ON和WHERE)均没有对os字段进行过滤性操作。在这种情况下,如果在select list中没有对os字段进一步做SUM/AVG/COUNT等聚合操作(可以是MIN/MAX/DISTINCT等聚合操作),那么可以去掉left join算子,改写成如下形式:

代码语言:javascript代码运行次数:0运行复制

SELECT t1.os d0FROM music_impala.left_join_table1 t1GROUP BY t1.osLIMIT 20000

3

小结

本文简单说明了Impala的系统架构和元数据管理,介绍了我们内部版本引入的集中式管理服务器。重点介绍了在分析型数仓技术中执行引擎这块的主要技术点和常见优化方法,并结合Impala展开进行了分析,包括动态代码生成、基于准入控制的资源管理、基于统计信息的代价计算、查询并行执行、SQL优化和错误重试等。

下一篇我们会重点分析由云原生数仓Snowflake引入的虚拟数仓特性。

作者简介

荣廷,网易杭研数据库开发专家。10年数据库和存储开发经验,2013年起一直从事数据库内核和数据库云服务相关工作,现为杭研数据库内核团队负责人;专注于数据库内核技术和分布式系统架构,乐于挑战和解决疑难问题;负责网易MySQL分支InnoSQL的开发和优化工作,大幅提升了线上业务的MySQL数据库服务质量;主导并推动MGR、MyRocks等新方案在考拉海购、云音乐、传媒等业务场景大规模使用;累计申请10+技术发明专利(已授权8个),《MySQL 内核:InnoDB 存储引擎 卷1》作者之一。

本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://cloud.tencent.com/developer/article/2091598

以上就是基于Impala的高性能数仓实践之执行引擎模块的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/19228.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月1日 01:19:23
下一篇 2025年11月1日 01:20:03

相关推荐

  • CSS mask属性无法获取图片:为什么我的图片不见了?

    CSS mask属性无法获取图片 在使用CSS mask属性时,可能会遇到无法获取指定照片的情况。这个问题通常表现为: 网络面板中没有请求图片:尽管CSS代码中指定了图片地址,但网络面板中却找不到图片的请求记录。 问题原因: 此问题的可能原因是浏览器的兼容性问题。某些较旧版本的浏览器可能不支持CSS…

    2025年12月24日
    900
  • Uniapp 中如何不拉伸不裁剪地展示图片?

    灵活展示图片:如何不拉伸不裁剪 在界面设计中,常常需要以原尺寸展示用户上传的图片。本文将介绍一种在 uniapp 框架中实现该功能的简单方法。 对于不同尺寸的图片,可以采用以下处理方式: 极端宽高比:撑满屏幕宽度或高度,再等比缩放居中。非极端宽高比:居中显示,若能撑满则撑满。 然而,如果需要不拉伸不…

    2025年12月24日
    400
  • 如何让小说网站控制台显示乱码,同时网页内容正常显示?

    如何在不影响用户界面的情况下实现控制台乱码? 当在小说网站上下载小说时,大家可能会遇到一个问题:网站上的文本在网页内正常显示,但是在控制台中却是乱码。如何实现此类操作,从而在不影响用户界面(UI)的情况下保持控制台乱码呢? 答案在于使用自定义字体。网站可以通过在服务器端配置自定义字体,并通过在客户端…

    2025年12月24日
    800
  • 如何在地图上轻松创建气泡信息框?

    地图上气泡信息框的巧妙生成 地图上气泡信息框是一种常用的交互功能,它简便易用,能够为用户提供额外信息。本文将探讨如何借助地图库的功能轻松创建这一功能。 利用地图库的原生功能 大多数地图库,如高德地图,都提供了现成的信息窗体和右键菜单功能。这些功能可以通过以下途径实现: 高德地图 JS API 参考文…

    2025年12月24日
    400
  • 如何使用 scroll-behavior 属性实现元素scrollLeft变化时的平滑动画?

    如何实现元素scrollleft变化时的平滑动画效果? 在许多网页应用中,滚动容器的水平滚动条(scrollleft)需要频繁使用。为了让滚动动作更加自然,你希望给scrollleft的变化添加动画效果。 解决方案:scroll-behavior 属性 要实现scrollleft变化时的平滑动画效果…

    2025年12月24日
    000
  • 如何为滚动元素添加平滑过渡,使滚动条滑动时更自然流畅?

    给滚动元素平滑过渡 如何在滚动条属性(scrollleft)发生改变时为元素添加平滑的过渡效果? 解决方案:scroll-behavior 属性 为滚动容器设置 scroll-behavior 属性可以实现平滑滚动。 html 代码: click the button to slide right!…

    2025年12月24日
    500
  • 为什么设置 `overflow: hidden` 会导致 `inline-block` 元素错位?

    overflow 导致 inline-block 元素错位解析 当多个 inline-block 元素并列排列时,可能会出现错位显示的问题。这通常是由于其中一个元素设置了 overflow 属性引起的。 问题现象 在不设置 overflow 属性时,元素按预期显示在同一水平线上: 不设置 overf…

    2025年12月24日 好文分享
    400
  • 网页使用本地字体:为什么 CSS 代码中明明指定了“荆南麦圆体”,页面却仍然显示“微软雅黑”?

    网页中使用本地字体 本文将解答如何将本地安装字体应用到网页中,避免使用 src 属性直接引入字体文件。 问题: 想要在网页上使用已安装的“荆南麦圆体”字体,但 css 代码中将其置于第一位的“font-family”属性,页面仍显示“微软雅黑”字体。 立即学习“前端免费学习笔记(深入)”; 答案: …

    2025年12月24日
    000
  • 如何选择元素个数不固定的指定类名子元素?

    灵活选择元素个数不固定的指定类名子元素 在网页布局中,有时需要选择特定类名的子元素,但这些元素的数量并不固定。例如,下面这段 html 代码中,activebar 和 item 元素的数量均不固定: *n *n 如果需要选择第一个 item元素,可以使用 css 选择器 :nth-child()。该…

    2025年12月24日
    200
  • 使用 SVG 如何实现自定义宽度、间距和半径的虚线边框?

    使用 svg 实现自定义虚线边框 如何实现一个具有自定义宽度、间距和半径的虚线边框是一个常见的前端开发问题。传统的解决方案通常涉及使用 border-image 引入切片图片,但是这种方法存在引入外部资源、性能低下的缺点。 为了避免上述问题,可以使用 svg(可缩放矢量图形)来创建纯代码实现。一种方…

    2025年12月24日
    100
  • 如何让“元素跟随文本高度,而不是撑高父容器?

    如何让 元素跟随文本高度,而不是撑高父容器 在页面布局中,经常遇到父容器高度被子元素撑开的问题。在图例所示的案例中,父容器被较高的图片撑开,而文本的高度没有被考虑。本问答将提供纯css解决方案,让图片跟随文本高度,确保父容器的高度不会被图片影响。 解决方法 为了解决这个问题,需要将图片从文档流中脱离…

    2025年12月24日
    000
  • 为什么我的特定 DIV 在 Edge 浏览器中无法显示?

    特定 DIV 无法显示:用户代理样式表的困扰 当你在 Edge 浏览器中打开项目中的某个 div 时,却发现它无法正常显示,仔细检查样式后,发现是由用户代理样式表中的 display none 引起的。但你疑问的是,为什么会出现这样的样式表,而且只针对特定的 div? 背后的原因 用户代理样式表是由…

    2025年12月24日
    200
  • inline-block元素错位了,是为什么?

    inline-block元素错位背后的原因 inline-block元素是一种特殊类型的块级元素,它可以与其他元素行内排列。但是,在某些情况下,inline-block元素可能会出现错位显示的问题。 错位的原因 当inline-block元素设置了overflow:hidden属性时,它会影响元素的…

    2025年12月24日
    000
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 为什么使用 inline-block 元素时会错位?

    inline-block 元素错位成因剖析 在使用 inline-block 元素时,可能会遇到它们错位显示的问题。如代码 demo 所示,当设置了 overflow 属性时,a 标签就会错位下沉,而未设置时却不会。 问题根源: overflow:hidden 属性影响了 inline-block …

    2025年12月24日
    000
  • 如何利用 CSS 选中激活标签并影响相邻元素的样式?

    如何利用 css 选中激活标签并影响相邻元素? 为了实现激活标签影响相邻元素的样式需求,可以通过 :has 选择器来实现。以下是如何具体操作: 对于激活标签相邻后的元素,可以在 css 中使用以下代码进行设置: li:has(+li.active) { border-radius: 0 0 10px…

    2025年12月24日
    100
  • 为什么我的 CSS 元素放大效果无法正常生效?

    css 设置元素放大效果的疑问解答 原提问者在尝试给元素添加 10em 字体大小和过渡效果后,未能在进入页面时看到放大效果。探究发现,原提问者将 CSS 代码直接写在页面中,导致放大效果无法触发。 解决办法如下: 将 CSS 样式写在一个单独的文件中,并使用 标签引入该样式文件。这个操作与原提问者观…

    2025年12月24日
    000
  • 如何模拟Windows 10 设置界面中的鼠标悬浮放大效果?

    win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…

    2025年12月24日
    200
  • 为什么我的 em 和 transition 设置后元素没有放大?

    元素设置 em 和 transition 后不放大 一个 youtube 视频中展示了设置 em 和 transition 的元素在页面加载后会放大,但同样的代码在提问者电脑上没有达到预期效果。 可能原因: 问题在于 css 代码的位置。在视频中,css 被放置在单独的文件中并通过 link 标签引…

    2025年12月24日
    100
  • 为什么我的 Safari 自定义样式表在百度页面上失效了?

    为什么在 Safari 中自定义样式表未能正常工作? 在 Safari 的偏好设置中设置自定义样式表后,您对其进行测试却发现效果不同。在您自己的网页中,样式有效,而在百度页面中却失效。 造成这种情况的原因是,第一个访问的项目使用了文件协议,可以访问本地目录中的图片文件。而第二个访问的百度使用了 ht…

    2025年12月24日
    000

发表回复

登录后才能评论
关注微信