当前位置: 首页 > 科技观察

前车之鉴--EverDB的分布式执行计划

时间:2023-03-14 11:04:58 科技观察

在数据库系统设计中,执行计划是对SQL执行过程的形式化描述,包括SQL执行所需的所有运算符及其执行顺序。我们可以通过“EXPLAIN+SQL”命令详细查看其执行计划,找到性能瓶颈,为我们优化SQL提供方向和依据。本文将从EverDB分布式数据库的角度来讲解执行计划。(1)分布式架构执行计划与中心化数据库相比,分布式数据库拥有大量的分片节点,分片节点负责各自分片的数据计算和存储,因此其执行计划需要特殊的实现方式。对于中间件架构的分布式数据库,通过引入分布式算子(即下面的EverDB执行计划节点)实现数据分片存储功能,执行计划分析优化,下发数据分片内部独立计算,协调数据分片间的并发执行,执行结果再由中间件进一步整合,进行分组、排序等操作,是一种高效便捷的实现方式。EverDB就是基于这种设计思想的执行计划。与传统的中心化数据库相比,EverDB执行计划使得数据库具有更高的可扩展性,支持更大的数据规模,以及更高的并发数据访问。在处理相同负载压力的前提下,可以充分利用各个分片的存储和计算资源,以及并行计算的优势,获得更好的性能。(2)EverDB执行计划EverDB分布式数据库由Grid调度层、数据节点、配置节点、管理控制台组成。Grid调度层作为分布式数据库的调度节点,接收和解析SQL,重构和转换SQL语句,支持涉及分片表和非分片表两种类型的执行计划分析。图1EverDB的执行计划包括SQL在Grid调度层和后端数据节点的执行过程。Grid调度节点的执行计划主要涉及两部分:逻辑处理层和连接驱动层。计划树和计划树节点。其中,普通表/分片表配置用于识别SQL是否需要分片,获取分片表的存储地址信息,根据分片策略完成执行计划的构建。连接驱动层是内部连接池和通信协议的处理模块,完美支持MySQL通信协议,负责将请求下推到执行计划中的数据节点。数据节点执行计划的实现可以参考MySQL执行计划。图2以分片查询为例,EverDB的Grid调度节点的执行计划流程:SQL解析:客户端处理线程接收客户端发送的查询请求,对SQL进行词法语法分析。SQL重构:根据SELECT查询表的存储信息,可以分为普通表和分片表。如果是分片表,需要根据查询条件和数据存储条件,进一步重构和优化SQL语句。例如,多个分片之间的跨节点查询,可以通过SQL重构后的数据节点下推,或者通过创建临时表并迁移一小部分数据来减少查询性能损失。构建执行计划:SQL解析完成后,需要构建对应的执行计划树,即用于维护SQL执行计划的数据结构,由多个执行计划节点组成。执行计划节点是SQL执行过程中每一步的执行者,也可以看作是每个线程的执行体。它分为多种类型,用于执行不同的操作,如内部执行节点、事务执行计划节点、数据迁移执行节点、信息查询节点、信息发送节点、组合排序去重节点等。运行执行计划:在执行计划运行过程中,通过多线程并发查询分片表,加快分布式集群的处理速度。SQL下推:EverDB为了将查询请求下推到对应的分片数据节点,通过通信模块(即MySQL协议适配和驱动模块)将查询请求封装成MySQL通信协议格式的数据包在图3中)。然后连接池分配的连接将数据包发送给数据节点,完成分片查询请求的下推。集成结果:数据节点收到调度节点的请求,进一步进行SQL解析,形成表的执行计划。查询计算完成后,数据节点将查询结果反馈给调度节点,调度节点继续根据执行计划树对所有数据节点返回的分片结果进行合并、排序等操作,并将完整的查询结果返回给客户端。完成查询请求。图3当调度节点生成执行计划树时,会根据分片规则对语句进行并行执行转换,将重构后的多条SQL从相应的执行计划叶子节点下推到目标实例,并通过数据节点实例分片查询执行计划分析。图4介绍了执行计划叶子节点下推查询请求到数据节点的通信过程。COM_QUERY是封装查询语句的协议包,从执行计划叶子节点发送到对应的数据节点进行查询计算。执行计划叶节点通过MySQL协议流程接收并解析结果集。图中结果集返回的协议包及其顺序为:ResultSetHead:结果集头包,包含列号信息;Field:结果集字段包,包括每个字段的具体信息,结果集的每个字段对应一个Field协议包;发送完所有字段信息后,后端数据节点发送EOF协议包,开始发送行数据;RowData:结果集行数据包,与Field协议包相同,每行数据对应一个行数据包,因此,一次结果集传输可能包含多个行数据协议包;所有行数据包发送完毕后,服务器会发送一个EOF协议包,表示结果集传输结束;执行计划叶子节点收到分片查询结果后,将各自的分片结果交给父非叶子节点对所有分片结果做进一步处理(如合并、排序等),返回完整的查询数据结果给客户。图4(3)如何查看执行计划?要显示执行计划,只需在查询的SELECT关键字之前添加DBSCALEEXPLAIN。具体语法如下:DBSCALEEXPLAIN+SELECT查询语句;结果包括执行计划每一步的执行信息,显示执行节点、执行顺序和执行SQL内容,通过执行计划也可以看到SQL的性能。分析SQL语句和表结构的性能瓶颈。图5是上图(图5)的一个例子,执行计划返回的结果分为上、下结果集。第一部分展示了查询请求从中间层Grid到数据节点的完整执行计划。结果集的前两列是SQL在中间层Grid中的执行计划,即exec_node字段显示SQL的执行计划树,data_source显示每个shard执行节点涉及的shard数据源。结果集的其他字段显示了每个分片查询在各自数据节点上的执行计划,与MySQLexplain返回的结果相同。第二部分显示的是执行计划实际运行在各个执行节点上的重构SQL语句,因此可能与从客户端收到的SQL语句不同。执行计划中一些重要字段的说明如下:exec_node:执行计划树的各个执行节点。整列显示完整的执行计划树,以“*”开头的表示执行计划树的根节点,以“-”开头的表示执行计划树的子节点,其中短横线越长,节点层更深。如上例所示,*MySQLSendNodeid的首字母为*,即本例中分片查询执行计划树的根节点。--MySQLFetchNode以“--”开头,是执行计划树的子节点。多个FetchNodes并发查询对应数据节点的数据分片,SendNode整合多个FetchNodes的查询结果。data_source:数据源信息。数据源是提供数据库连接具体执行客户端请求的数据库实例,即执行查询的MySQLFetchNode实例地址。id:select子句或操作表在查询中的执行顺序。如果id相同,则执行顺序为从上到下;如果id不同,id值越大,优先级越高,越早执行。select_type:查询数据的操作类型,如下表所示:如果SIMPLE查询不包含子查询或UNIONPRIMARY查询包含任何复杂子部分,则最外层查询标记为PRIMARYSUBQUERY并在SELECT中包含子查询或WHERE列表中,子查询被标记为SUBQUERYDERIVEDFROM列表中包含的子查询被标记为DERIVED(派生)UNION如果第二个SELECT出现在UNION之后,则被标记为UNION;如果UNION包含在FROM子句的子查询中,则外层SELECT将被标记为DERIVEDUNIONRESULT从UNION表中获取结果的SELECT被标记为UNIONRESULT表示查询中每个select子句的类型(简单OR复杂)table:执行节点处理的表名。type:数据节点在表中查找所需行的方式,也称为“访问类型”,意思是|所有|索引|范围|参考|eq_ref|常量,系统|空|从左到右,从最坏到最好。常见类型如下:ALLFullTableScan,数据节点会遍历整个表寻找匹配的行索引从某一点开始,返回匹配某个值范围的行,常见于between,<,>等查询。ref非唯一索引扫描,返回匹配单个值的所有行。通常使用非唯一索引,即使用唯一索引的非唯一前缀来执行lookupEq_ref唯一索引扫描。对于每个索引键,表中只有一条记录与其匹配;常见于主键或唯一索引扫描Const,系统作为数据节点优化查询的某一部分并将其转换为常量时,使用这些类型的访问;如果主键放在where列表中,数据节点可以将查询转化为常量,system是const类型的特例,当查询表只有一行时,使用systemNULL数据节点分解优化过程中的语句,执行时甚至不需要访问表或索引possible_keys:表示数据节点可以使用哪个索引来查找表中的行,如果查询涉及的字段上有索引,索引将被列出但不一定被查询使用。key:显示数据节点在查询中实际使用的索引。如果没有使用索引,则显示为NULL注意:如果查询中使用了覆盖索引,则该索引只会出现在键列表中。key_len:表示索引使用的字节数,通过它可以计算出查询中使用的索引的长度。key_len显示的值是索引字段的最大可能长度,不是实际使用的长度,即key_len是根据表定义计算的,不是从表中取出来的。ref:表示上述表的连接匹配条件,即使用哪些列或常量来查找索引列上的值。rows:表示数据节点根据表统计和索引选择,估计需要读取多少行才能找到需要的记录。Extra:数据节点解决查询的详细信息,尽量避免:UsingFileSort,UsingTemporary。第二部分包括node_id和sql两个字段:node_id与第一部分exec_node字段方括号中的序号相关联,表示SQL语句在exec_node的每一层执行。具体的SQL语句内容显示在“sql”字段中。当“sql”字段中出现临时表dbscale_tmp(dbscale_tmp是EverDB的保留字)时,说明当前SELECT查询涉及到跨分片查询,系统性能损耗较大。需要进一步分析SQL语句和表结构的性能瓶颈,尽量避免使用。临时表,示例如下。图6-4概括了EverDB作为一个典型的基于中间件实现分库分表方案的分布式数据库产品。与传统的中心化数据库相比,其执行计划的不同之处在于,它在底层包含了SQL在分片表上的执行步骤,同时也包含了代理如何对SQL进行分布式处理,以提高分布式数据库的处理性能。是EverDB独特的基于中间件的执行计划实现方式。无论EverDB的执行计划是来自底层数据节点还是来自中间层,在SQL优化算法上还有很多值得优化和改进的地方。未来,EverDB将不断完善自身的各项能力,努力成为更优秀的国产分布式数据库产品。