ABSTRACT:
连接顺序选择对查询性能起着非常重要的作用。然而,现代的查询优化器通常使用静态的连接顺序枚举算法,并没有包含也有关质量的反馈。因此优化器经常会重复的选择一个糟糕的计划,因为他们没有从错误中进行学习的机制。在这里,我们认为(argue)深度强化学习技术可以用来应对这一挑战。这些由人工神经网络支持的技术可以通过结合反馈来自动的改善优化器的决策执行。为了实现这一个目标,我们提供了ReJOIN,一个概念验证连接枚举器,以及初步的结果表面ReJOIN可以匹敌或者比PostgreSQL优化器更好,在plan的quality以及连接枚举的效率方面。
INTRODUCTION:
引文相关工作:确定关系查询的良好连接顺序是数据库系统中研究的比较深的问题。引文[6,12,13,18],因为所选的连接顺序对查询性能有着很大的影响。
连接顺序选择的一个主要挑战:枚举一组候选顺序并确定最具成本效益的顺序。搜索更大的候选空间会增加找到低成本排序的几率,但是代价是在查询优化上需要花费更多的时间(因为需要的候选多了?)
所以连接枚举器的作用:同时寻找最小化plans的枚举的数量以及最小化chosen plan的最终成本。
两个方向,优化的方向都是最小化:1.plan的数量2.plan的成本。
传统的连接方式:
使用各种连接枚举策略,例如System R[18]用动态规划来寻找成本最低的左深连接树,贪婪的选择低成本的关系对,直到构建一棵树。许多商业产品,如引文[3],允许DBA控制size of the candidate plan space 通过structural constraints,例如仅限左深的计划,或者是在一段时间之后切断枚举来控制候选计划空间的大小。
局限性:这些启发式算法往往会错过良好的执行计划。更重要的是,传统的查询优化器依赖于静态的策略,因此无法从过去的经验中学习。传统的系统plan a query,执行这个query plan,然后忘记他们曾经优化过这个查询。由于缺乏反馈,一个查询优化器可能会不断地重复选择一些坏的计划,从来没有从他之前的好的坏的选择中进行学习到一些东西。
在本文中,我们分享了一个基于学习的优化器,它能够利用之前的经验,目的在于学习怎么来优化未来的查询更有效的(例如,更好的查询计划)以及更效率的(在优化上用更少的时间)。用DRL(深度强化学习)来以较少的优化时间来提供更好的查询计划。
第一步,作者提出了一个ReJOIN,一个概念证明连接顺序选择器,完全是由深度强化学习来进行驱动的。在第二个部分,我们描述了ReJOIN。在第三部分,我们提供了一些有希望的初步的结果表明ReJOIN可以比PostgreSQL的连接枚举器在效率和有效性方面。
The ReJOIN Enumerator(重新连接枚举器)
许多现代的DBMS采用传统的基于成本的查询优化方法,具体来说就是给定一个SQL查询作为输入,a join order enumerator 查收所有可能的join orderings的子空间,然后选出最便宜的顺序(根据成本模型)执行。此枚举并不执行索引选择,连接运算符的选择(join operator selection)等等。这些任务会交给DBMS优化器的其他部分来进行执行。一个join ordering 被一个二叉树所捕获,其中每一个叶子结点都代表着一个base relation。图1展示了三种可能的join orderings对于关系A,B,C和D。
什么叫强化学习?
强化学习假设了一个agent和一个环境进行交互。环境会告诉agent他目前的state,以及一组可能的actions这个agent可能会采取的。agent会挑选一个action,然后环境会给agent一个reward,这个reward是基于这个action的。然后环境还会additionally给这个agent一个新的状态和一个新的动作,这个过程会一直重复直到agent达到terminal的状态,在这个状态下没有任何action可以采取。这标志着一个episode的结束,在这之后一个新的episode会开始。agent的目标是最大化这个reward,reward是经过episodes之后的,通过从他之前的experience进行学习,这个之前的经验包括之前的行动,状态以及回报。这是通过平衡探索新的策略和利用目前现有的知识来进行完成的。什么是探索新的策略?就是那个人为设定的概率来探索一个非最优的action。
什么是利用目前现在的知识?就是目前回报期望最高的那个action,但是未必是最好的,可能利用一定的概率来探索新的可能性会获得更好的结果。
Overview:
我们将join order的enumeration过程描述为一个强化学习的问题。每一个被发送给优化器的查询都会代表一个episode,以及ReJOIN会不断的学习当queries被发送的时候。每一个state会代表着一个二叉连接树的子树,除了有关查询连接和选择谓词。每一个action都会代表着combing两个子树一起变成一个single tree。一个子树表述输入关系和一个子树之间的连接。这个episode会结束,当所有的输入关系都被连接的时候,这时候就代表着一个终结状态。在这个时候,ReJOIN会给最终的join ordering一个回报基于optimizer’s 的cost model。最后的join ordering会发送给optimizer,然后生成的物理计划会由DBMS来进行执行。
ReJOIN的框架如图所示,形式上给定一个查询q访问关系r1,r2,...,rn,我们定义这个初始状态of the episode for q as s1={r1,r2,...,rn}。这个state被表示的形式是一个state vector。这个state vector被fed through一个神经网络,这会产生可能的动作的概率分布。动作action的集合对于任意的state是每个唯一有序的整数对从1到|Si|,也就是Si的长度,包括
动作action(x,y)属于动作集合i,表示将xth和yth的元素of si连接在一起。神经网络的输出备用来挑选一个新的动作(例如,一个新的join),他会被返回给环境,然后会变成一个新的状态。状态Si+1,在经过选择完一个(x,y)之后,是Si+1=(Si-{S[x],Si[y]})并上{Si[x]自然连接Si[y]}。细新的状态会被fed给神经网络,每一个非终结状态的reward都是0,以及rewardfor一个action到达终结状态时the join tree t的cost的倒数。代理会periodically的tweak神经网络的权重从而目的是获得更大的回报。
图3,显示了一个潜在的episode,对于一个query设计关系ABCD的来说。初始的状态是S1={A,B,C,D}。状态集合set 1包含着一个元素对for each ordered pair of relation,例如(1,4)属于动作集合1,代表着对A和D进行连接,动作(2,3)也属于动作集合1,代表着将B和C进行连接。代理选择了动作(1,3)代表着选择连接A和C。下一个状态是S2={A自然连接C,B,D}。agent接下来会选择动作(2,3)代表着进行连接B和D。下一个状态就是S3,他仅仅包含两个元素,一个是{A自然连接C},一个是{B自然连接D},也就是说S3={A自然连接C,B自然连接D}。在这个时候,代理只有两种可能性的选择A3={(1,2),(2,1)},因为里面只有两个元素。假设代理会选择(1,2),那么下一个状态S4={(A自然连接C)自然连接(B自然连接D)}。
At this point,the agent would receive a reward based on the cost model's evalutaion of the final join ordering.
在这个时候,agent会得到一个reward,这个reward是基于一个成本评估模型对于最终连接序列的评估得到的。
2.1 State Vectors
ReJOIN需要一个向量表示,这个向量表示是关于每个状态的,他抓住了状态的信息,这个信息是关于join树的结构也就是连接树的结构,以及连接选择的谓词。接下来,我们outline了一个简单的vectorization strategy,这个向量化的策略可以捕获这些所需要的信息,以及展示强化学习策略可以非常有效即使输入的数据是有限的。demonstrates that reinforcement learning strategies can be effective even with limited input data.
Tree Structure
为了抓住树的结构数据,我们对每一个二叉子树都进行编码(即迄今位置的决定的join ordering)(join ordering decided so far),二叉子树定义为x,x是属于Sj的,Sj是上面的一个连接数。作为一个行向量v,size是n。n是数据库中的关系的总数。如果第ith个关系还没有在x中,那么他的value i就是0.否则的话,就是等于h(i,x)的倒数,h(i,x)是关系ri在子树x的高度(也就是离根结点的距离)在图中的示例,第一行的tree vector例如第二个图,A和C都是1/2,因为A和C的高度都是2,而B和D在A连接C这个子树中的高度都是0因为他们没有被包含进这个树里面。
Join Predicates连接谓词
为了捕获有关连接谓词的关键信息,我们创建了一个n*n的二进制堆成矩阵m,对于每个episode。To capture critical information about join predicates,we create an n*n binary symmetric matrix m for each episode.
这个矩阵m的第i行j列,是一如果一个连接谓词连接了第i和第j个关系,否则的话就是0。
The value mi,j is one if there is a join predicate connecting the ith and the jth relation,and a zero otherwise.
选择谓词:Selection Predicates
选择谓词的向量是一个k维的向量,k是数据库中的属性的总数,也就是所有关系中的属性的总数。The ith value是1,如果第ith的属性有一个选择谓词在给定的查询中,否做是0。
The ith value is one when the ith attribute has a selection predicate in the given query,and zero otherwise.
这揭示了哪个属性是否被用来过滤元组。例如在图中,有B.a2>100的选择操作,所以B.a2的值就是1。
This reveals which attributes are/are not used to filter tuples.For example,in Figure the value corresponding to B.a2 is one because of the predicate B.a2 >100.
Reinforcement Learning
重新连接依赖于策略梯度方法,这是强化学习的一个特定的子集。
policy gradient methods:直接输出动作,如果action很多,DQN要计算所有的action的概率会造成很大的复杂度。policy gradient methods的核心思想就是如果一个行为是好的(也就是reward比较大),那么下次会对这个行为的概率进行加大。反过来也是如此,如果一个行为是坏的那么就减少他所发生的概率。
策略梯度强化学习的代理基于参数化的policy P@,其中@是一个向量代表着policy parameters。给定一个状态St,以及一个动作集合at。那么策略函数P@会输出一个得分对于每个动作(在动作集合中的每个动作),在本文的情况中,这个得分就是一个score for combining two join subtrees。也就是这个得分就是连接两个子树的得分。然后使用这种方法进行操作的选择。
强化学习的目标是来优化策略函数通过episodes,例如来identify 这个policy parameters @ that optimizes the expected reward J.然而,reward J 通常无法精确的计算,因此policy gradient methods search for the optimal policy parameters by constructing an estimator E of the gradient of the reward:E() = 求梯度J。
给定一个estimate E,gradient ascent的方法tune the 初始的参数@,通过增加@i的每个参数by a small value当梯度是正向的(正向的梯度意味着a larger value of @i will increase the reward),以及减少@i的参数通过一个小的值当梯度是负向的时候。
Policy gradient deep learning
策略梯度深度学习方法将参数派表示为一个神经网络,参数@是神经网络的权重,因为有了参数@的存在所以使得policy能够有效的被区分(也就是policy是否在这个学习中是有效的)。
图示表示了我们用在ReJOIN中的policy 神经网络。目前状态的向量化表示被送入到了state layer层,在这里每一个value都被transformed然后被送入了第一个隐藏层。第一个hidden layer transforms 然后passes its data to the second hidden layer,在第二个隐藏层后会pass data to the final action layer。每一个神经元在action layer中的神经元都代表一个可能的action,然后他们的输出都被标准化后成了一个概率的形式。The policy函数(si,Ai)以一个概率的形式来进行抽样从而平衡exploration和exploitation。(DCN的方式是选择一个最好的?然后有一定的概率来选的别的差的,但是policy gradient的方式是全都以概率的形式进行选择)
policy gradient的梯度下降是,is estimated using samples of previous episodes(queries)。也就是随着每次查询的过程会进行梯度下降,每个episodes都代表一个queries。每次,一个episode被完成(也就是意味着一个join ordering for given query is selected),the ReJOIN agent都会记录一个新的观察结果。Given a set of experiences over multiple episodes X=***,不同的高级的方式可以用来对梯度E(reward的梯度E)来进行estimate,
RELIMINARY RESULTS
在这里,作者提供了初步的实验,表明他们提出的ReJOIN可以生成连接排序,而且他的成本和延迟于PostgreSQL的优化器所生成的连接排序是一样好的甚至更好。
我们的实验用了Join Order Benchmark,连接顺序基准,这是一组查用用语之前对query optimizers 的assessments之中。这个benchmark包括113个query instances of 33 query templates over the IMDB dataset。
什么叫Join操作?
JOIN会对两张或者两张以上的表进行连接操作。
什么叫查询优化?
为什么查询的速度会变慢?
一个查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端。其中在执行的阶段,包含了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组等。
查询速度慢的原因在于:某些不必要的额外操作,以及某些操作被额外的重复了很多次,某些操作执行的太慢了,优化查询的目的就是减少和消除这些操作所话的时间。
慢查询基础:优化数据访问
查询性能底下的最基本的原因就是访问的数据太多了,所以对于低效的查询可以从下面两个方面分析:
1.确认应用程序是否在检索大量超过需要的数据。
2.确认MySQL服务器层是否在分析大量超过需要的数据行。
3.是否向数据库请求了不需要的数据。
因为,请求多余的数据会给MySQL服务器带来额外的负担,并增加网络开销,另外也会消耗应用服务器的CPU内存和资源。低效的查询表现在如下方面:
1.查询不需要的记录:例如在新闻网站中取出100条记录,但是只是在页面上显示10条。实际上MySQL会查询出全部的结果,客户端的应用程序会接收全部的结果集数据,然后抛弃其中大部分的数据。
2.多表关联的时候返回全部列。
3.总是取出全部的列。
4.重复查询相同的数据:不要不断底重复执行相同的查询,然后每次都返回完全相同的数据。当初次查询的时候将这个数据缓存起来,需要的时候从缓存中取出,这样性能显然更好。所以,在查询语句的时候要慎用select *语句,我们对数据库的数据应该只取所需。
MySQl是否在扫描额外的记录:
在确定查询只返回需要的数据之后,那么查询为了返回结果是否扫描了过多的数据,有以下三个指标来衡量查询的开销:
1.响应时间:
响应时间是两个部分的和1)服务时间2)排队时间,一般常见和重要的等待是IO和锁等待。
2.扫描的行数。
分析查询的时候,查看该查询扫描的行数是非常有帮助的,一定程度上能够说明该查询找到的数据的效率高不高。理想情况下,扫描的行数和返回的行数是相同的,但是一般来说都是在1:1到1:10之间。
3.返回的行数。
可以通过查询慢日志来找到这三个指标的记录。