Steering Query Optimizers: A Practical Take on Big Data Workloads【论文内容翻译】

文章研究了在SCOPE大数据处理系统中应用机器学习优化查询优化器的方法。通过分析SCOPE的查询优化器规则,引入规则签名概念,并设计了一个管道来发现对工作负载有益的规则配置。实验表明,通过选择不同的规则配置,可以显著减少作业的运行时间,平均节省7-30%,最高可达90%。这种方法依赖于学习模型来选择规则配置,旨在提高执行效率,而不需要深入更改优化器本身。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

标题:指导查询优化器:对大数据工作负载的实用处理

***摘要***:近年来,人们对将机器学习应用于数据库系统的研究产生了极大的兴趣。作为DBMS中最复杂的组件之一,查询优化器可以系统地从数据和查询工作负载中学习的自适应策略中获益。最近的研究提出了一些关于学习查询优化器的新想法,但是这些想法还没有在商业查询处理器或大规模的实际工作负载上进行评估。在本文中,我们采用Marcus等人在Bao中使用的方法,并将其应用于微软内部使用的大数据系统SCOPE。在此过程中,我们解决了多个新的挑战:我们通过引入规则签名的概念来定义优化器规则如何影响最终的查询计划,我们为重复出现的作业设计了一个计算有趣规则配置的管道,我们定义了一个新的学习问题,允许我们将这些有趣的规则配置应用于以前未见过的作业。我们评估了该方法在生产工作负载上的有效性,其中包括150𝐾 日常作业。我们的结果表明,可选的规则配置可以以较低的成本生成计划,这可以转化为平均节省7 - 30%的运行时间延迟,对于工作负载的一个重要子集,可以节省高达90%的运行时间延迟。

介绍

级联式查询优化器[7]在商业和开源数据库系统中都很流行,例如Spark[31]、Calcite[2]、Greenplum[25]、Snowflake[4]、F1[23]、SQL Server[17]和SCOPE[3]。它们的核心是一组规则,用于枚举所有有效的查询计划。使用成本模型和估计基数,为每个计划分配一个成本作为计划的中间结果。优化器选择执行成本最低的计划。优化器可能会犯多种类型的错误,例如基数错误估计、成本模型中的不准确性[13]以及其他糟糕的启发式方法。这些错误可能会对优化器所做的低级决策产生很大的不利影响,例如算子实现和连接顺序的选择。例如,严重的基数低估可能导致优化器选择包含嵌套循环连接的灾难性计划[14]。

近年来,一些研究尝试使用机器学习来解决这类问题:例如,学习基数[11],学习成本模型[24],甚至学习查询规划器[12,14,15]。特别是Bao[14]方法,通过限制基于给定查询的查询优化器的搜索空间来处理许多优化器缺陷。这是通过禁用优化器规则的一个子集来实现的,这些规则控制如何转换查询计划,例如,优化器使用哪些算子或算法。例如,Bao可以了解到,某些类型的查询 系统地存在很大的低估,并决定关闭其他类似查询的嵌套循环连接。因此,我们可以构建复杂的机器学习模型来深入影响查询计划,而无需对查询优化器进行深入更改。

本文填补了指导查询优化器的最新研究进展与行业实力查询优化器的实际情况之间的空白。具体来说,我们考虑了微软用于PB级大数据处理的SCOPE[3]查询引擎,分析了SCOPE查询优化器的当前状态,并将Bao中的思想应用于SCOPE中的生产工作负载。在这样做的同时,我们解决了多个新的挑战。我们为查询引入规则签名的概念,即影响优化器最终查询计划输出的一组规则。规则签名一直是我们发现有趣规则配置的所有启发式方法的核心。更重要的是,它被证明是一个很好的信号,可以将非常不同的查询聚类到组中,其中相似的规则配置可以带来改进。直观地说,规则签名可以简洁地捕获查询在优化器中使用的代码路径。此外,我们设计了一个管道,可以自动从历史作业中提取有趣的配置,然后可以在线使用它来改进未来重复出现的作业。最后,我们建立了一个学习问题,并提供了一些关于机器学习如何通过利用我们的离线管道的结果来改进以前未见过的作业的初步结果。

我们在几个星期的时间窗口内对从生产集群中采样的三个工作负载评估了我们的方法的有效性。对于任何一天,这些包括150𝐾 SCOPE作业(表1),包含20𝐾 小时的总处理时间,跨越超过5亿个容器。这些作业也比评估Bao或其他几种学习查询优化方法[11,14,15,18]时使用的工作负载复杂得多,每个SCOPE作业多达数百个算子。此外,与Bao中考虑的48种PostgreSQL配置相比,有数十亿条有效规则配置的巨大搜索空间。

我们在不同的工作负载中发现了强有力的证据,表明通过选择不同的规则配置来控制SCOPE优化器的搜索空间可以显著改善执行时间。此外,我们可以可靠地识别跨许多天运行的重复作业的模板,其中某些规则配置可以导致一致的改进。为了说明这一点,图1显示了工作负载A 中一周内的65个作业,其中相同的规则配置将每个查询的执行时间缩短了几个小时,运行时间缩短了50%到90%。总体而言,我们对三种生产工作负载的分析表明,平均而言,在运行时间超过5分钟的作业中,有近10 - 20%的作业可能会有10 - 30%的运行时间改进,这是工作负载中关键的资源密集型组件。

总结起来,我们的主要贡献是:

  1. 规则签名。分析了规则在SCOPE查询优化器中的使用,并介绍了SCOPE作业的规则签名思想。规则签名既可以对作业进行特征化,也可以对作业进行集群化,因为它可以简洁地捕获有关优化器内部代码路径的有用信息。

  2. 发现有趣的规则配置。我们创建了一个启发式驱动的管道,它使用查询计划的重新编译和选择性重新执行来发现有趣的规则配置。我们提供了强有力的证据和直觉,说明为什么不同的规则配置可以提高SCOPE中的性能。这些技术不依赖于我们对这些规则的现有知识,并且可能扩展到数百个更多的规则,或其他配置标记和设置。此外,我们确定了跨多个星期的重复查询,这些新规则配置可以提供运行时间改进。

  3. 学习。在更具有挑战性的情况下,相同的规则配置也可能导致未见过查询的回归。因此,我们将在编译时选择规则配置表述为一个学习问题,并给出我们使用学习模型为新查询选择规则配置的结果。这些结果只使用了总工作负载的一小部分,但是我们的结果表明,它可以扩展到整个生产工作负载。

组织。本文的其余部分组织如下:在第2节中,我们描述了相关工作,特别是我们的方法所基于的Bao系统的相关特征。在第3节中,我们给出了SCOPE的背景,特别是我们描述了它基于规则的优化过程。在第4节中,我们描述了为SCOPE调整类似Bao的系统所面临的挑战,在第5、6和7节中,我们描述了解决这些挑战的方法。论文在第8节以结论和未来的工作结束。

相关工作

  • Learned query optimization

最近的许多工作使用学习模型来改进基数估计[5,6,11,18,19,27,29,30],这是查询优化的核心组成部分。其他方法[12,15,16]侧重于通过学习成本模型或运行时间的输出直接生成查询计划。我们的方法基于Bao[14],并使用现有的优化器基础设施来更好地探索和选择优化器已经考虑的查询计划。从概念上讲,这类似于过去探索查询计划空间的工作,例如Picasso[8],或者为选择查询计划设计健壮的成本估计[26]。

  • Bao

Marcus等人[14]将Bao设计为一个利用PostgreSQL查询提示生成48个提示集(或规则配置)的系统。每个提示集本质上就像一个简单版本的PostgreSQL查询优化器。每个简单的优化器禁用PostgreSQL标记的一个子集。提示会影响选择扫描算子、连接算子和连接顺序的优化器行为。他们将每个简单的优化器视为多臂强盗问题中的一只手臂。给定一个新的查询,模型学习从48个手臂中选择一个。它被建模为一个强化学习问题,在这个问题中,Bao看到一系列查询,并随着时间的推移学会做出正确的决定。Bao在一个自定义数据集上进行评估,查询时间从几秒到几百秒不等。Bao没有依赖于PostgreSQL的成本模型。相反,他们系统的核心组件是一个树状卷积神经网络,它通过执行计划来学习树形结构PostgreSQL查询计划的成本模型。

  • SCOPE

SCOPE的总体设计由Chaiken等人[3]描述。Jindal等人[9]概述了用于在SCOPE中引入工作负载优化的Peregrine基础设施。已经有一些尝试在SCOPE中引入学习组件的努力。Sen等人[22]使用学习模型自动选择作业应该使用的并发容器数量。Wu等人[28]开发了一种针对SCOPE工作负载进行基数估计的新方法。Siddiqui等[24]分析了基于云的执行框架下成本模型面临的新挑战,并提出了SCOPE的学习方法。

生产查询处理器

在本节中,我们首先描述SCOPE查询处理器,以及它在生产环境中看到的工作负载。然后,我们分析了SCOPE中的优化器规则,最后讨论了应用ML在SCOPE优化器规则空间中导向的关键要求。

3.1 SCOPE Overview and Workloads

SCOPE是一个大型分布式数据处理系统。它支持来自一系列微软产品的生产工作负载,每天数PB的数据[3]。SCOPE使用一种类似sql的脚本语言,它被编译成算子的直接无环图(DAG)。SCOPE脚本包含关系算子和用户定义算子的混合(在C#和Python中)。由于SCOPE脚本包含多个SQL语句的数据流,因此它们也被称为作业。

SCOPE优化器的结构与传统的级联式查询优化器非常相似:它以自顶向下的方式使用多个任务转换逻辑查询计划。但是,SCOPE优化器还会做出有关如何划分输入的所有决策,并根据作业可用的容器数量选择最优的并行度。每个作业使用的并发容器的数量称为SCOPE中的令牌数量。SCOPE优化器使用数据特征和多年来优化的其他启发式方法的组合来估计算子捕获其运行时间延迟的成本。对于任何查询计划(或子计划),算子的成本都将与其所有子计划的成本递归地组合在一起,最终优化器将选择执行总成本最低的计划。

3.1.1 SCOPE Workload Characterization

SCOPE工作负载的很大一部分由反复出现的作业组成,即具有不同输入和谓词的周期性到达模板,这些模板是内部客户端工作流程的一部分。它们通常用于处理大量原始数据、运行数据挖掘或其他分析任务,以及填充仪表板以进行交互式分析。这些作业的输入数据流每天都在变化。可以通过丢弃所有变量值(例如,谓词过滤器)和计算查询图中剩余信息的散列来识别属于同一模板的重复作业。

  • Short running jobs v/s long running jobs

在图2a中,我们显示了一天中工作负载A中的运行时间分布。最短的作业只需要几秒钟,但有几个作业可以运行几个小时。类似的结果也适用于其他工作负载。不出所料,运行时间较短的作业消耗的资源也更少。我们发现只有大约10%的作业持续时间超过5分钟,但这些作业消耗了工作负载中使用的总容器的90%。此外,分布式处理通常会导致相同查询计划的运行时间出现差异(资源分配中的不可预测性、集群条件导致的热点或大型数据依赖链)。顺便说一句,短时间运行的作业也有较大的方差:例如,在工作负载B上,我们观察到的方差约为10%。因此,我们在这项工作中重点关注长时间运行的作业。

3.1.2 Metrics

作业运行时间是用于评估性能的典型指标。然而,在SCOPE中,以下其他指标同样重要,特别是在监视资源使用方面的成本时。通常,在同一组资源上执行许多并行作业,因此提高任何资源的利用率有助于提高其他作业的性能,并减少服务器上的负载。

  1. Runtime:从开始到结束执行作业的总时钟延迟。这还不包括作业在调度队列中可能花费的时间。

  2. CPU time:这是SCOPE作业中所有顶点的总CPU时间,表明该作业的计算成本,对于度量集群中的CPU利用率非常有用。

  3. Total I/O time:这包括读取、写入或复制到不同容器的数据,并指示I/O花费的时间。

3.1.3 A/B testing Infrastructures

SCOPE基础架构还提供了A/B测试功能,以评估SCOPE引擎中新特性的性能影响,例如,在新的SCOPE发布期间。此特性还可用于执行具有不同配置的作业,并比较性能。A/B测试基础设施可以使用生产数据集重新执行最近的生产作业,但将输出重定向到虚拟位置[1,10,22,28]。我们在本文的所有实验中都使用了这种A/B测试基础结构。

对于所有报告的执行时间(或适用时的其他指标),我们在生产集群上重新执行原始生产查询计划和备用查询计划(使用不同的规则配置),并使用相同的可用资源集(每个作业50个令牌)。在生产中,每个作业使用不同的资源执行,这是由客户端指定的,但是我们通常发现,使用固定资源集的改进也会在使用更多资源时转化为改进。

3.2 Analyzing SCOPE Optimizer Rules

现在我们分析SCOPE中的查询优化器规则。SCOPE优化器中有256条规则,用于管理优化SCOPE作业的算法和算子。这些规则涵盖了广泛的标准优化器规则:重写规则、特定算子的规则、连接顺序和实现规则等等。它还涉及SCOPE特定算子的算子和算法,如union all[3]。图2b显示了每条规则在Workload A作业中使用的频率分布,图2c显示了单个作业中使用多少条不同规则的分布。有趣的是,尽管在工作负载中经常使用100 - 150条规则,但在单个作业中通常只使用10 - 20条不同的规则。我们将SCOPE中使用的规则类型分为四个非正式的类别。

  1. Required rules:这些规则对于查询处理中的正确性是必要的,因此我们不将它们视为可学习规则配置的一部分。示例包括EnforceExchange或BuildOutput,它们没有可选规则。

  2. Off-by-default rules:这些规则要么是实验性的,要么是不安全的,因为它们对基数的错误估计非常敏感。一个例子是一组稍有不同的CorrelatedJoinOnUnion规则。这些规则选择在join operator下推union all operators,即选择在每个分布式节点上进行联合,然后将它们合并到单个节点上进行连接,而不是在每个分布式节点上进行连接,然后在合并的结果上应用union算子。该规则的性能可能对中间结果的大小非常敏感。

  3. On-by-default rules:其中包括大多数优化规则和算法。示例包括各种重写规则、连接顺序规则、聚合和排序规则。

  4. Implementation rules:这些规则是关于逻辑算子的物理实现的,比如join或union all。对于每个算子类型,必须启用其中一个实现规则。为简单起见,本文将它们视为一类规则。

表2总结了一天中工作负载A 中95𝐾 作业中每个类别的一些统计信息。有趣的是,在此工作负载中从未使用过许多默认规则。

  • Definition 3.1 - 规则配置

我们定义了一个位向量,指定在优化给定作业时每个规则是启用还是禁用,作为规则配置。SCOPE中的默认规则配置有46个被禁用的规则(默认规则关闭),其余规则是启用的。优化器只能使用已启用的规则。SCOPE公开标记或“提示”,允许最终用户指定在优化作业时应该启用或禁用哪些规则,因此可以在SCOPE中轻松地修改规则配置。

有些规则,例如一些重写规则,并不适用于作业(例如,因为目标算子不是查询的一部分)。在其他情况下,有些规则没有使用,因为使用了替代规则(例如,连接算子实现规则)。为了跟踪这一点,我们修改了SCOPE优化器,以记录哪个规则对最终查询计划的任何组件有贡献。

  • Definition 3.2 - 规则签名

我们定义一个位向量,指定哪些规则直接促成优化器生成的最终查询计划作为规则签名。如果在位向量中为1,我们将它们称为on规则,否则称为off规则。例如,考虑一个总共有10条规则的场景。将使用这10条规则的特定规则配置来优化给定的查询,例如,1111111110 — 这意味着禁用最后一条规则,启用其余规则。并非所有启用的规则都会影响优化过程——例如,有些规则可能并不适用于这个特定的查询。假设在优化过程中只使用了第一条和第二条规则。然后,使用给定的规则配置,该查询的规则签名将为1100000000。我们将使用默认规则配置优化的查询的规则签名称为默认规则签名。

图2d显示了工作负载A 中一天内作业的默认规则签名的分布情况。尽管可能的规则签名呈指数级增长,但在实践中,我们观察到规则签名的分布中存在许多结构。例如,有几个规则签名,每天有近1000个作业映射到它们。

3.3 Learning Requirements

在像SCOPE这样的复杂且广泛使用的系统中引入任何学习组件都是具有挑战性的。下面我们讨论一些我们的需求。

  • Domain knowledge vs full control:与Bao相比,另一种方法Neo[15]是从头开始学习完整的优化器,或者它的完整组件。它受益于对优化决策的完全控制,但它不能使用SCOPE等商业优化器中使用的数十年精心制作的特定领域优化。Bao和我们在本文中的改编,利用了所有现有的知识和优化器的实现。

  • Non-invasive:SCOPE优化器有一个非常成熟和庞大的代码库。对优化器的内部进行重大更改并在特定子系统中包含学习,同时避免不必要的副作用,这是非常具有挑战性的。我们的方法学会了有效地使用优化器已经暴露的旋钮。

  • Ease of deployment as “plan hint”:部署基于学习的方法总是很困难的,这可能会导致令人惊讶的回归问题。部署这种系统的一种方法是向负责特定工作负载的客户端建议新的规则配置。事实上,虽然规则标记已经可用并且经常被客户端使用,但是新的规则配置可以简单地作为此功能的扩展而出现。

  • Scalability:新的代码路径不断添加到优化器中,导致复杂性不断增加。除了规则之外,优化器还有数百个其他可配置的标记和代码路径。我们的方法被设计成可以扩展到所有可用的标记。

  • Focus on relevant metrics:最近的一些工作集中在改进查询优化器的成本模型和基数估计组件[11,18,19,29,30],包括SCOPE[24,28]。这些仍然是具有挑战性的问题,并且很难以改进整个查询优化过程的方式修复这些错误。更重要的是,改进单个组件(如基数估计)并不能保证生成的计划变得更好。相反,我们的学习方法试图直接优化我们关心的指标(例如,执行时间、I/O)。

指导查询优化器

在本节中,我们将描述使用规则提示指导查询优化器的问题,讨论我们在SCOPE中看到的挑战,并概述解决这些挑战的方法。

  • Problem Statement

给定一个新的SCOPE作业,SCOPE优化器总是使用默认规则配置来生成查询计划。我们的目标是输出一个可选的规则配置,它可以更好地优化这个特定的作业和给定的指标,比如运行时间延迟。

虽然上述问题陈述与Bao[14]中的相同,但在为SCOPE处理它时,我们发现了几个新的挑战。我们将在下面讨论它们。

  1. Large space of rule configurations:我们在SCOPE中考虑影响比Bao更广泛的优化器行为的规则。SCOPE有219条非必需规则,因此对配置的数量有2^{219}个理论限制。由于隐式依赖关系,其中许多可能无法成功编译,但是仍然有数十亿条有效的规则配置(与Bao中考虑的48条规则配置相比)。因此,我们需要一种方法来提出一组候选规则配置,这些规则配置可能值得进一步探索。同时,大空间的可能性也使它更容易发现有趣的行为。

  2. Expensive Executions:对于太多的规则配置,收集关于执行时间的数据是非常昂贵的。因此,我们将没有足够的数据来学习成本模型,如Bao。相反,我们需要启发式方法来选择应该执行哪些规则配置。

  3. Formulating the learning problem:由于配置的数量,多臂强盗问题不会扩展到像SCOPE这样的系统。SCOPE查询图是具有多达数百个算子节点的DAG,因此像Bao中那样基于图的特征化方案并不直接适用。

概述我们的方法。为了克服上述挑战,我们采取了四个主要步骤:

  1. Which jobs and rule configurations should we look at?我们选择一个具有代表性的工作子集来分析。对于每个规则,我们使用启发式方法生成多达1000个候选规则配置。(第5节)。

  2. Can rule configurations improve runtimes?我们使用启发式方法选择10个候选规则配置来执行,并找到能够改进作业运行时间的配置。(第6.1、6.2节)。

  3. Extrapolate to other jobs. 我们采用改进了运行时间的配置,并将其外推到跨多天的其他作业和可能受益于这些配置的模板中。(6.4节)。

  4. Learn. 我们收集多天作业的运行时间数据,并训练一个监督学习模型来选择规则配置。(第7节)。

上面描述的管道通过利用SCOPE的编译器、标记和A/B测试基础设施来分析过去的工作负载,从而脱机运行。然后,我们可以在在线场景中使用学习到的模型来自动地为新作业使用不同的规则配置,或者向客户端推荐新的配置。

发现规则配置

原生的方法是为每个作业考虑指数级多的有效规则配置。显然,这是不可行的。因此,我们的目标是自适应地为给定作业发现𝑀个有趣的规则配置。然后,我们使用𝑀中每个规则配置重新编译作业,并分析生成的查询计划,以找到值得执行的计划。

5.1 Job Span

直观地说,我们希望找到可以在优化的查询计划中导致有趣更改的规则配置,同时不探索太多不值得的配置。也就是说,我们只想研究启用/禁用对最终查询计划有影响的规则的配置。禁用不会影响查询计划的规则不会产生任何影响(例如,为没有group by子句的作业优化group by 算子的规则)。我们描述了如何通过简单的启发式方法对规则的搜索空间进行修剪

Definition 5.1 - Job span

给定一个作业,其范围包含所有非必需的规则,如果启用或禁用这些规则,则会影响最终的查询计划。

为优化器(如SCOPE优化器)生成作业范围是一项挑战,其中规则可能具有复杂的数据驱动依赖关系。算法1展示了我们用来近似作业范围的启发式方法。我们已经知道,默认规则签名中的所有on规则都会影响最终的查询计划。因此,如果我们禁用其中一些规则,优化器可能会使用其他一些规则来代替。该算法通过迭代地禁用优化作业时使用的所有规则并每次重新编译作业,以查看哪些新规则开始被使用来查找此类替代规则。

Limitation:上述算法没有捕获可能影响最终查询计划的所有可能规则,因为规则中可能存在复杂的依赖结构,但不能通过我们的启发式方法间接观察到。例如,考虑三个规则A、B、C,其中B和C是可选规则,但它们都依赖于A,因此只有在使用规则A时才能使用它们。假设启用了所有规则,A和B位于规则签名中。在第一次迭代中,启发式算法通过禁用规则A和规则B来计算作业范围。因此,它将无法发现规则C也会影响最终计划。为了解决这个缺点,我们需要更详细地了解规则及其依赖关系,尽管缺少这些复杂的依赖关系,但我们已经可以使用启发式方法找到许多有趣的规则配置,正如我们在5.3节中的分析中所示。

5.2 Configuration Search

相对于规则的总数,大多数查询在其范围内的规则要少得多。例如,图3显示了一天内工作负载A上每个作业范围内规则数量的平均值和标准偏差。我们按照前面描述的规则类别对这些规则进行分组。平均而言,我们看到每个作业只使用了219条非必需规则中的20条规则。这大大减少了规则配置的搜索空间。

  • Assuming independence of rule categories

非正式地说,如果启用或禁用其中一个规则不会影响查询优化器中另一个规则的行为,则可以认为两个规则是独立的。这可能是因为它们适用于工作的不同部分。直观地说,查询优化器中一定有很多规则,这些规则通常是独立的:例如,特定的连接实现规则可能独立于某些重写规则。知道规则子集是独立的可以极大地减少规则配置的搜索空间。例如,考虑5条规则。有2^{5} = 32个规则配置。如果我们能确定有两组规则,两个和三个规则,使得这两组规则相互独立。然后,我们只需要探索2^{2} + 2^{3} = 12个规则配置。虽然很难正式建立和发现这些独立的规则子集,但在这项工作中,我们假设每一类规则都独立于其他类别。在实践中,这使得探索规则空间变得更加容易。

  • Randomized Configuration Search

我们使用随机搜索枚举𝑀个候选配置。对于给定的作业,规则配置列表由以下方式生成:

  1. 启用不在给定作业范围内的所有规则。

  2. 对于每个规则类别,分别从作业范围中采样一个规则子集。禁用这些规则,并启用所有其他规则。这给了我们一个新的规则配置。

  3. 如果是以前没有见过的规则配置,则将其添加到候选列表中。重复此操作,直到生成𝑀个配置。

5.3 Recompilation Results

  • Selecting jobs to analyze

我们在一天内从工作负载A、工作负载B和工作负载C中对作业进行初步分析。我们过滤掉时间快于5分钟和时间超过1小时的作业。我们避免使用短时间运行的作业,因为运行时间的差异使得很难区分不同查询计划之间的改进。我们避免长时间运行的作业,因为重新执行许多备选计划可能会花费很长时间。从剩余的作业中,我们从每个工作负载中随机选择10 - 20%的查询样本。我们为每个要重新编译的作业生成多达1000个唯一规则配置。令人惊讶的是,对于大多数查询,使用新规则配置的一些重新编译的计划具有较低的估计成本。图4显示了带有默认成本的来自工作负载A的查询示例,以及每个规则配置的重新编译成本。这似乎是自相矛盾的,因为像SCOPE这样的级联式优化器保证它在搜索空间中找到估计成本最低的计划。

  • Why does the optimizer find lower cost plans with different configurations?

更改规则配置可以通过一些微妙的方式影响估计成本的计算方式。SCOPE优化器保证在搜索空间中找到估计成本最低的计划,但这只适用于给定的基数估计和启发式集合。更改规则配置可能会影响这些,因此使用不同规则重新编译的成本无法直接比较。新配置可以降低成本的几种方式是:

  1. Changing node properties:查询图中的每个节点都具有各种逻辑和物理属性,例如基数估计或成本,这些属性是根据SCOPE的启发式和假设估计的。替代规则配置可以改变这些属性的计算方式,这自然会导致不同的成本估计。例如,更改过滤器的顺序可能会影响每个节点的基数估计(由于相关性、倾斜或其他原因),从而影响估计的成本。

  2. Degree of Parallelism:不同的规则会影响查询计划的分布式特性。这包括如何将输入分配到不同的容器,使用的并行度,以及为作业启动的容器数量。然而,同样不可能详尽地研究所有分布式选项。SCOPE的搜索空间启发式地选择几个并行度来探索。由于启发式依赖于逻辑属性,如基数估计,因此有可能使用不同的规则配置,选择不同程度的并行性。

在SCOPE中使用不同的规则配置找到较低的估计成本计划是和Bao之间的一个关键区别。在PostgreSQL中,在Bao中考虑的不同规则配置下,估计的成本是可以直接比较的。但是,没有禁用任何标记的计划将是成本最低的计划(但不是最佳计划,因为错误的估计或错误的成本模型假设可能意味着其他计划可以执行得更快),因为当前的提示集仅限于扫描和连接,并且它们不影响节点属性[14]。

执行规则配置

在前一节中,我们看到了如何探索大型规则配置空间,并以较低的估计成本发现有趣的配置。在本节中,我们将深入研究这些有趣的规则配置对运行时间性能的影响。

6.1 Choosing rule configurations to execute

Bao的关键组成部分之一是学习成本模型,该模型允许系统在不同的规则配置中进行选择[14]。这是可能的,因为只有很少的规则配置,查询的执行时间要短得多。因此,Bao可以收集关于不同类型查询和规则配置的详尽数据来训练他们的模型。但在SCOPE中这是不可能的,因为在生产工作负载中有成千上万的昂贵工作,而且用于A/B测试的预生产资源有限。因此,我们使用启发式方法来选择执行哪些作业,以及它们重新编译的SCOPE计划中的哪些。

  • Using the cost model

尽管使用不同规则配置重新编译的计划的估计成本不能直接比较,但它仍然是关于计划质量的有用信号。更便宜的计划,或者接近默认计划的成本,表明优化器认为新计划至少不是一个坏计划。作业是通过以下启发式方法选择的:

  1. Cheaper plans:我们从重新编译的计划明显比默认计划便宜的作业中进行采样(在估计成本中,差异大于特定于工作负载的阈值)。执行这样的计划是有直观意义的,如果只是为了发现更低的成本是否意味着更快的运行时间。

  2. Jobs with low cost, high runtimes:图5显示了一天中工作负载A中所有作业的默认规则配置的估计成本和运行时间的散点图。注意,左上角的作业:这些是成本较低的情况,也就是说,优化器期望它们运行得快,但实际上运行时间要高得多。由于成本模型对这些工作的预测是错误的,这表明一些成本模型假设并不成立。我们从具有适当的成本和运行时间阈值的此类作业中进行采样。

对于上面选择的每个作业,我们选择10个最便宜的可选规则配置并执行它们。这让我们可以为每个工作探索一套不同的合理计划。我们总共在211个作业中选择了2110个规则配置,用于预生产环境中的A/B测试。

6.2 A/B Testing Results

执行所有可选配置总共需要3960小时的执行时间。每个工作负载都有不同类型的工作,但我们在所有这些工作中都观察到类似的趋势。图6显示了已执行作业的运行时间从默认规则配置到最佳规则配置的变化百分比。请注意,运行时间的最大可能改进可以导致100%的更改(因为运行时间不能是负的),但是回归可以大于100%。

  • Runtimes

至少有一种可选规则配置可以改善大多数作业的运行时间。我们看到了类似的趋势,甚至在工作负载A和工作负载B中也有很大的改进。有些作业的速度提高了90%——这意味着绝对运行时间节省了几个小时。工作负载C的工作显示出相同的趋势,但改进(和回归)的幅度较小。这部分是因为我们在工作负载C中分析了更少的作业,但也因为更长的运行时间导致更低的百分比变化(例如,将10分钟的作业改进5分钟将带来50%的改进,而将10小时的作业改进1小时仅带来10%的改进)。

  • Different Metrics

在第3节中,我们描述了SCOPE中感兴趣的多个度量。在图7中,我们放大了Workload B的结果,以探索更改规则配置如何影响所有这些指标。一个自然的问题是:所有的指标是否都得到了改善?我们为每个作业执行了10个可选配置。我们将展示在为 运行时间(图7a)、CPU时间(图7b)或 I/O时间(图7c)  选择最佳配置时,100个作业的每个指标是如何变化的。在很多情况下,我们可以看到每个指标的改进(从上到下的绿色条形图)。但更多情况下,所有指标之间存在一种内在的紧张关系。在图7a中,我们可以看到运行时间得到改进的 许多作业的CPU时间和I/O时间的 回归(红色条)。在图7b中,对于CPU时间,这些回归似乎基本上消失了,因为对于每个作业,我们选择了导致最佳CPU时间的10种配置中的一种。和以前一样,我们仍然看到I/O时间上的回归,但是现在我们在运行时间也看到了更多的回归。图7c显示了类似的模式。

这呈现了一个复杂但有趣的优化场景。我们可能有单独的模型,分别对每个指标进行优化,并根据上下文选择使用哪一个。例如,当服务器上有高负载时,我们可能希望最小化其中一种资源(CPU时间,I/O时间),而当负载较少时,我们可能只想要最快的运行时间。更复杂的策略可能会考虑客户需求等等。我们也可以想象设计一个损失函数来平衡每个指标的相对重要性,并尝试在所有指标中做到最好。探索这些想法超出了本研究的范围。

  • When the cost model is completely wrong

成本模型可能是错误的,在这种情况下,选择最便宜配置的启发式方法可能会错过成本模型认为昂贵的好计划。为了探索这个场景,我们选择了20个随机作业,并为它们执行了几个随机选择的候选配置。我们只发现了一个替代方案明显更好的例子。虽然学习一个SCOPE的成本模型并使用它来选择有趣的规则配置(类似于在Bao中所做的)有很多潜力,但这个实验也表明,要找到这样的例外情况要困难得多。因此,我们决定将注意力集中在通过尝试基于成本模型输出的规则配置而发现的更好的规则配置上。

  • Summary

表3显示了所选作业的运行时间变化,以及与默认运行时间相比的百分比变化,如果我们总是选择最佳规则配置(包括默认配置,因为正如我们所看到的,对于某些作业,任何不同的规则配置都不会带来改进)。平均而言,我们看到工作速度提高了7 - 35%,其中包括速度提高了90%的工作。这些改进将使运行时间平均改进400到1700秒,许多作业将改进几个小时——这对SCOPE客户来说是一个显著的改进。

6.3 Why do different rule configurations improve job runtimes?

让我们更深入地研究更改规则配置对性能的影响。查询优化器中不同规则的交互可能很复杂,因此很难确定是什么导致了不同的紧急行为。我们可以将这些规则配置视为在优化器中探索略微不同的路径。一种假设是,通过禁用规则,我们只是阻止了某些路径——这些路径可能是由于优化器中的错误估计或启发式而被选择的。这可能会推动优化器为给定的作业找到更好的路径。如果优化器的基数估计和成本模型假设都是完美的,那么优化器可能自己发现最佳路径——但这是不现实的。尽管如此,我们还是观察到一些有趣的模式,它们可以提高工作表现。

  • Do lower estimated costs always result in lower runtimes?

不。正如§5所描述的,有很多原因可以降低估计成本,而这些并不符合更好的计划。我们使用较低的估计成本作为潜在有趣的替代方案的信号。

  • Which rules change in jobs with improvements?

当一个新的规则配置导致比默认配置更快的运行时间,我们可能想知道哪些更改导致了改进。我们可以直接比较两种配置的启用或禁用规则。但是并不是规则配置中的所有更改都是有意义的。例如,禁用规则可能对生成的查询计划没有影响。或者,两个配置之间可能有十个不同之处,但其中只有一个会导致查询计划的更改。我们定义RuleDiff是为了只查看哪些规则更改实际影响了查询计划。

Definition 6.1 - RuleDiff :对于给定的作业和新规则配置,我们将使用默认规则配置获得的规则签名位向量与使用新规则配置获得的规则签名进行比较。在两个位向量中对应的位相等的规则不受新规则配置的直接影响。在默认规则签名位向量中为1,但在新配置的位向量中为0的规则没有在新的查询计划中使用。这可能是因为这些规则被禁用了。这些规则仅在默认计划中被称为规则。只有新计划中的规则定义相似。

在表4中,我们显示了为每个工作负载中的特定作业找到的最佳配置的规则差异。对于来自工作负载A的Q_{A1},我们看到在最佳计划中看到了一个额外的规则,而在默认计划中使用了许多额外的规则。最佳计划中的附加规则是off-by-default 规则,这解释了为什么它不在默认计划中。

  • Is enabling off-by-default rules enough for Q_{A1} ?

不。我们有几个配置也为Q_{A1}启用了相同的off-by-default规则,并禁用了不同的规则子集。所有这些结果的运行时间都比默认配置快,但比最佳配置慢7−9倍。对于SCOPE优化器团队中的专家来说,为什么这个特定的规则配置会导致具有最快运行时间的计划,这一点并不明显。这突出了这些规则以非常复杂的方式交互的事实,并且很难手动配置这些规则。

  • Disabling rules is crucial

一些最大的收益来自于禁用规则。这在RuleDiffs中清晰可见,许多规则只出现在默认计划中,而不在最佳计划中。在Q_{A2}中,最佳计划中没有使用额外的规则;相反,我们使用了6条更少的规则,这使得运行时间提高了近90%。这支持了我们的假设,即这些规则配置帮助提高性能的一种方式是阻止可能导致给定作业的糟糕计划的优化路径。

  • Alternative rules.

对于作业Q_{A3}Q_{B3},规则UnionAllToVirtualDataset出现在最佳计划中,而UnionAllToUnionAll出现在默认计划中。这两个规则在默认情况下都是开启的。基于成本模型,优化器一定认为UnionAllToUnionAll是更好的选择,但是对于这个任务的一些假设或估计是错误的。我们的方法并没有纠正这些错误,而是禁用了导致优化器做出决策的规则——从而引导它在最终计划中使用其他规则。类似的基序也被观察到Q_{B2}

6.4 Extrapolating to other jobs

在前一节中,我们发现了一天内作业子集脱机的良好规则配置。查找这些配置的过程非常昂贵,特别是因为它需要为每个作业执行来自许多可选规则配置的计划。为了使其有用,我们需要在编译时为新作业生成这些规则配置。因此,我们试图了解其他场景,在这些场景中,我们可以利用导致改进运行时间的规则配置。显然,它们并不是对工作负载中的每个工作都有用。在另一个极端,跨越了许多天,这些配置似乎通常在来自相同的重复模板的作业上工作得很好。然而,正如我们在表1中看到的,有成千上万个这样的模板,通常每个模板每天只有一个或几个作业。因此,发现和学习每个模板的规则配置是不可伸缩的。此外,即使作业中的微小差异,例如单个不同的输入名称,也会导致不同的重复模板标识符——即使作业可能几乎相同。因此,我们选择规则签名作为粒度级别,在此级别上,相同的规则配置集可能是有用的。

Definition 6.2 - Rule signature job group :这是一组作业,其默认规则签名映射到相同的位向量。我们将其称为工作组。

  • Are the jobs with the same rule signature similar from an optimizer’s perspective?

一个作业组可以有许多具有不同运行时间的模板、输入和作业。这显然不是一个同质组,但从优化器的角度来看,它们可能具有相似的属性,这是很直观的。相同的规则签名意味着这些作业具有相似的算子,并且在查询优化器中沿着相似的路径运行。与此同时,这可能并不总是正确的-这激发了学习的需要。

我们使用第6.1节的结果来选择基本作业,其中替代配置可以改善运行时间。从基本作业中,我们派生出它们所属的作业组。我们推断,这些配置对于跨多天使用相同规则签名的其他作业也很有用。基本作业和新的未见过的作业之间的共享规则签名,还意味着新配置不仅仅是随机更改—在新配置中禁用或启用的规则被选中,因此它们会影响基本作业中使用的规则。

  • Is learning needed?

当我们将新的规则配置应用于新的未见过的作业时,在多个星期内,我们观察到两个场景:

  1. The new configuration does not cause regressions:在某些情况下,导致基本作业的运行时间改进的配置似乎在给定工作负载的作业组中的所有作业上都能很好地工作。第1部分的图1中显示了来自工作负载A的一个示例。这些规则配置似乎对同一工作组中几乎四周随机抽样的所有工作都有好处。这是一个理想的情况,我们可以在没有太多回归风险的情况下获得我们的方法的好处。显然,随着这些工作的谓词和输入流的发展,这种行为在未来可能会发生变化。这种风险可以通过每周重新运行我们的管道来降低。

  2. New configuration can cause a regression:更常见的情况是,配置导致某些作业得到改进,但同一作业组中的其他作业却出现倒退。在这种情况下,我们尝试使用学习模型根据新作业的输入特征在配置之间进行选择。这将在§7中进一步探讨。

  • What fraction of the daily jobs may be impacted?

我们对一天中随机选择的一小部分工作进行了上述分析。让我们对工作负载B作业进行一些粗略的计算,以估计这些规则配置可能对整个工作负载产生的影响。提高短期运行作业的性能并不是很关键,因为它们消耗的资源要少得多。每天约有10%,即1624个工作持续时间超过5分钟,这些工作分为300个不同的工作组。我们统一地对其中的一半进行了采样,并对838个作业运行了我们的重新编译管道。从中,我们使用启发式方法选择155个作业(约占20%)来执行10个最便宜的替代计划。我们发现120个作业的运行时间性能有所改善,变化幅度从- 3%到- 90%不等。这120个工作属于44个工作组。这表明至少10 - 20%的长时间运行的日常作业可以使用该管道进行改进。然而,本节中描述的改进依赖于执行多个计划。在实际系统中,我们每次需要选择一个规则配置。接下来,我们将其表述为一个学习问题,并进行一些非常初步的分析,以了解我们如何能够选择最佳的规则配置。

学习规则配置

在本节中,我们将看到如何学习在给定新作业时选择规则配置。

7.1 Formulating the learning problem

  • Dataset

为了训练学习模型,我们收集给定作业和规则配置组合的运行时间数据集。我们从Workload B中选择三个规则签名,并收集几周内查询的数据,这些查询的默认规则签名映射到这些规则签名(即,属于同一作业组的作业)。所有这些作业组每天都有十多个作业,并且没有一个规则配置总是导致改进。对于每个作业组,我们为一到三个作业运行管道,并找到导致改进的配置。我们为每个作业选择三个最快的(运行时间)配置——因此,我们为每个作业组获得𝐾个候选配置。然后,我们在两周的时间内从映射到这些作业组的所有作业中采样𝑀个作业,并为每个作业执行𝐾个配置。

  • Learning Problem

我们将每个工作组的样本数据集视为一个独立的学习问题。目标是为给定查询选择𝐾个候选配置之一。我们使用监督学习来训练一个模型,为每个工作组选择𝐾个配置。

7.2 Featurization

对于任何基于学习的方法,我们都需要突出每个工作。

由于Bao中只考虑与连接排序相关的决策,因此PostgreSQL查询计划是相对较小的树。相比之下,SCOPE查询计划是大型DAG,由100𝑠甚至1000𝑠的算子节点组成,包括广泛使用客户用户定义的算子。此外,SCOPE脚本被编译成优化的查询计划,该查询计划被转换为阶段DAG,并以分布式方式执行,SCOPE引擎从每个步骤中发出几段不同的日志,这些日志很难描述,甚至可能与给定任务的目的不相关。因此,描述SCOPE任务是一个具有挑战性的问题。

  • Feature vector

我们使用特征向量来捕获最重要的特征,以便在特定作业组样本的𝐾规则配置之间进行选择。这包括:(1)作业级别特征。这些是特定作业的全局属性,其中包括估计的输入大小、输入的散列和查询模板的散列。(2)规则配置特征。对于每个配置,我们使用计划的估计成本和表示默认配置的RuleDiff的位向量。(3)查询图特征。我们在特征向量中为每个可能的算子类型保留一个位置。这些包括算子id,以及算子所有重复的平均估计成本和基数。

  • Encoding features

我们对所有的连续特征进行编码,使用极小值归一化将其值在0到1之间缩放。对于小字母大小的分类特征,我们使用one hot 编码。对于具有较大字母大小的分类特征,我们使用确定性哈希方案将每个值编码为50个bins中的一个[21]。

7.3 Learning Model

  • Lightweight model

对于每个作业组,我们使用一个完全连接的神经网络,其隐藏层大小为1024。这些模型的大小约为30MB,需要一分钟的时间来训练。

  • Loss function

我们将学习视为一个回归问题,其目标是对一个查询去估计每个归一化的𝐾运行时间对应于𝐾可能规则配置。优化回归任务的一个典型方法是使用均方误差。但是,这试图获得每个候选配置的精确估计。这通常是不需要的,因为我们实际上只关心选择最快的配置。相反,我们使用连续版本的交叉熵损失,在PyTorch中称为二进制交叉熵损失[20]。

7.4 Learning Results

  • Setup

作业组1有201个作业和10种可能的规则配置,作业组2有75个作业和7种可能的规则配置,作业组3有157个作业和10种可能的规则配置。我们将所有三个工作组中的工作随机分成20%的验证集和40%的训练和测试集。我们在验证集上调整模型的超参数,并在测试集上报告结果。

  • Results summary

运行时间如表5所示,图8显示了对每个查询的默认运行时间的更改。总的来说,我们看到每个工作组都有所改善,但也总有一些倒退。

  • Job group 1

在很大一部分作业中,有很大的改进,在运行时间上最多快了一个小时。请注意,运行时间具有不同的规模,因此百分比改进的大小与绝对运行时间改进的大小并不一致(运行时间较短的作业可能具有较大的改进)。从表5可以看出,学习到的模型接近于做出最佳决策。

  • Job group 2

这些作业的运行时间要长得多——其中一个影响是,百分比值似乎比其他作业组要小。但我们发现,在多个作业中,改进时间最多可达2000秒,而回归时间似乎更短。

  • Job group 3

这似乎是最难优化的工作组。注意,没有绿色或红色条形图的作业——在这些情况下,我们的学习模型会推荐默认配置。但它确实发现,对于多个其他作业,时间可以缩短1000秒。与此同时,回归的幅度要小得多。但是,正如我们从表5中的最佳运行时间中看到的那样,还有可能进行更重大的改进。

结论及未来工作

在本文中,我们介绍了SCOPE优化器——一个支持云计算的工业级查询优化器——如何利用学习方法,如Bao[14]中介绍的方法。我们介绍了规则签名和作业范围的概念,它们帮助我们浏览大量的规则配置空间,有效地发现有趣的配置,甚至将它们推广到其他未见过的作业中。我们在三个生产工作负载上的结果表明,我们可以实现高达90%的更好的运行时间延迟,平均提高7 - 35%,同时只需要对SCOPE优化器进行最小的更改。

我们相信,本文概述的方向打开了许多大门,其中一些我们目前正在探索。例如,有多种方法可以改进用于生成作业范围和候选规则配置的启发式方法。这种改进可以发现规则的独立子集,这将使规则配置的空间更小,从而能够探索更好的配置。我们还计划使用来自执行结果的反馈来指导配置搜索的未来迭代。最后,SCOPE优化器中还有数百个额外的可配置选项,我们可以通过在候选配置中包含它们来生成有趣的行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值