TiDB-explain详解

1. 使用 EXPLAIN 来优化 SQL 语句

EXPLAIN 语句的返回结果提供了 TiDB 执行 SQL 查询的详细信息:算法

  • EXPLAIN 能够和 SELECT, DELETE, INSERT, REPLACE, 以及 UPDATE 语句一块儿使用;网络

  • 执行 EXPLAIN,TiDB 会返回被 EXPLAIN 的 SQL 语句通过优化器后的最终物理执行计划。也就是说,EXPLAIN 展现了 TiDB 执行该 SQL 语句的完整信息,好比以什么样的顺序,什么方式 JOIN 两个表,表达式树长什么样等等。详细请看 EXPLAIN 输出格式;分布式

  • TiDB 目前还不支持 EXPLAIN [options] FOR CONNECTION connection_id,咱们将在将来支持它,详细请看:#4351;函数

经过观察 EXPLAIN 的结果,你能够知道如何给数据表添加索引使得执行计划使用索引从而加速 SQL 语句的执行速度;你也能够使用 EXPLAIN 来检查优化器是否选择了最优的顺序来 JOIN 数据表。oop

2. EXPLAIN 输出格式

目前 TiDB 的 EXPLAIN 会输出 6 列,分别是:id,parents,children,task,operator info 和 count,执行计划中每一个 operator 都由这 6 列属性来描述,EXPLAIN 结果中每一行描述一个 operator。优化

3.概述

3.1Task 简介

    目前 TiDB 的计算任务隶属于两种不一样的 task: cop task 和 root task。cop task 是指被下推到 KV 端分布式执行的计算任务,root task 是指在 TiDB 端单点执行的计算任务。SQL 优化的目标之一是将计算尽量的下推到 KV 端执行。编码

3.2表数据和索引数据

    TiDB 的表数据是指一张表的原始数据,存放在 TiKV 中。对于每行表数据,它的 key 是一个 64 位整数,称为 Handle ID。若是一张表存在 int 类型的主键,咱们会把主键的值看成表数据的 Handle ID,不然由系统自动生成 Handle ID。表数据的 value 由这一行的全部数据编码而成。在读取表数据的时候,咱们能够按照 Handle ID 递增的顺序返回。索引

    TiDB 的索引数据和表数据同样,也存放在 TiKV 中。它的 key 是由索引列编码的有序 bytes,value 是这一行索引数据对应的 Handle ID,经过 Handle ID 咱们能够读取这一行的非索引列。在读取索引数据的时候,咱们按照索引列递增的顺序返回,若是有多个索引列,咱们首先保证第 1 列递增,而且在第 i 列相等的状况下,保证第 i + 1 列递增。内存

3.3范围查询

    在 WHERE/HAVING/ON 条件中,咱们会分析主键或索引键的查询返回。如数字、日期类型的比较符,如大于、小于、等于以及大于等于、小于等于,字符类型的 LIKE 符号等。值得注意的是,咱们只支持比较符一端是列,另外一端是常量,或能够计算成某一常量的状况,相似 year(birth_day) < 1992 的查询条件是不能利用索引的。还要注意应尽量使用同一类型进行比较,以免引入额外的 cast 操做而致使不能利用索引,如 user_id = 123456,若是 user_id 是字符串,须要将 123456 也写成字符串常量的形式。针对同一列的范围查询条件使用 AND 和 OR 组合后,等于对范围求交集或者并集。对于多维组合索引,咱们能够写多个列的条件。例如对组合索引(a, b, c),当 a 为等值查询时,能够继续求 b 的查询范围,当 b 也为等值查询时,能够继续求 c 的查询范围,反之若是 a 为非等值查询,则只能求 a 的范围。字符串

4.Operator Info

4.1TableReader 和 TableScan

    TableScan 表示在 KV 端对表数据进行扫描,TableReader 表示在 TiDB 端从 TiKV 端读取,属于同一功能的两个算子。table 表示 SQL 语句中的表名,若是表名被重命名,则显示重命名。range 表示扫描的数据范围,若是在查询中不指定 WHERE/HAVING/ON 条件,则会选择全表扫描,若是在 int 类型的主键上有范围查询条件,会选择范围查询。keep order 表示 table scan 是否按顺序返回。

4.2IndexReader 和 IndexLookUp

    Index 在 TiDB 端的读取方式有两种:IndexReader 表示直接从索引中读取索引列,适用于 SQL 语句中仅引用了该索引相关的列或主键;IndexLookUp 表示从索引中过滤部分数据,仅返回这些数据的 Handle ID,经过 Handle ID 再次查找表数据,这种方式须要两次从 TiKV 获取数据。Index 的读取方式是由优化器自动选择的。

    IndexScan 是 KV 端读取索引数据的算子,和 TableScan 功能相似。table 表示 SQL 语句中的表名,若是表名被重命名,则显示重命名。index 表示索引名。range 表示扫描的数据范围。out of order 表示 index scan 是否按照顺序返回。注意在 TiDB 中,多列或者非 int 列构成的主键是看成惟一索引处理的。

4.3Selection

    Selection 表示 SQL 语句中的选择条件,一般出如今 WHERE/HAVING/ON 子句中。

4.4Projection

    Projection 对应 SQL 语句中的 SELECT 列表,功能是将每一条输入数据映射成新的输出数据。

4.5Aggregation

    Aggregation 对应 SQL 语句中的 Group By 语句或者没有 Group By 语句可是存在聚合函数,例如 count 或 sum 函数等。TiDB 支持两种聚合算法:Hash Aggregation 以及 Stream Aggregation(待补充)。Hash Aggregation 是基于哈希的聚合算法,若是 Hash Aggregation 紧邻 Table 或者 Index 的读取算子,则聚合算子会在 TiKV 端进行预聚合,以提升计算的并行度和减小网络开销。

4.6Join

    TiDB 支持 Inner Join 以及 Left/Right Outer Join,并会自动将能够化简的外链接转换为 Inner Join。

    TiDB 支持三种 Join 算法:Hash Join,Sort Merge Join 和 Index Look up Join。Hash Join 的原理是将参与链接的小表预先装载到内存中,读取大表的全部数据进行链接。Sort Merge Join 会利用输入数据的有序信息,同时读取两张表的数据并依次进行比较。Index Look Up Join 会读取外表的数据,并对内表进行主键或索引键查询。

4.7Apply

    Apply 是 TiDB 用来描述子查询的一种算子,行为相似于 Nested Loop,即每次从外表中取一条数据,带入到内表的关联列中,并执行,最后根据 Apply 内联的 Join 算法进行链接计算。

    值得注意的是,Apply 通常会被查询优化器自动转换为 Join 操做。用户在编写 SQL 的过程当中应尽可能避免 Apply 算子的出现。