零、执行流程
-
获取全局TSO(Timestamp Oracle):
- 在分布式系统中,为了保持事务的一致性,TiDB 需要从 PD(Placement Driver)获取一个全局唯一的时间戳。
-
Parser 语法语义解析 -> AST(Abstract Syntax Tree)语法树:
- SQL 查询语句首先被解析器(Parser)解析成 AST,这是一个抽象语法树,表示了 SQL 语句的结构。
-
Compile 编译:
- 在编译阶段,AST 被进一步处理以生成执行计划。
- 点查:如果查询是点查(即只读取一行数据的操作,如通过主键或唯一索引进行的查询),则可以直接执行,无需生成复杂的执行计划。
-
非点查:对于非点查查询,编译器会生成执行计划。
- 逻辑优化:执行计划首先进行逻辑优化,如内外连接转换、谓词下推等。
- 物理优化:接着进行物理优化,根据统计信息(如直方图)和成本模型选择最佳的算子(如选择使用 Hash Join 还是 Sort Merge Join)。
- 在编译阶段,AST 被进一步处理以生成执行计划。
- 执行计划的执行:优化后的执行计划被发送到 TiKV 进行执行。TiKV 使用 Coprocessor 来执行计算任务,并将结果返回给 TiDB。
- 结果汇总与处理:TiDB 收到来自 TiKV 的结果后,进行汇总和处理,最终将查询结果返回给用户。
- 缓存与并发控制:在执行过程中,TiDB 还会利用缓存来加速查询,并通过并发控制机制来管理对数据的并发访问。
一、执行计划分析原则
- 先向右看:在执行计划中,首先关注并列的算子,优先执行上层的算子。
- 最向右先执行:在并列的算子中,最右侧的算子(即最靠近输出结果的部分)优先执行。
二、优化目标
TiDB 的计算任务主要分为两种:
- Cop Task:在 TiKV 中通过 Coprocessor 执行的计算任务。
- Root Task:在 TiDB 中执行的计算任务。
优化目标是将尽可能多的计算任务下推到 TiKV 中执行,因为 TiKV 的 Coprocessor 支持大部分 SQL 内建函数、LIMIT 操作、索引扫描和表扫描。
三、算子详情
TiDB (Root)
- TableReader:汇总 TiKV 上的 TableFullScan 或 TableRangeScan 算子的数据。
- IndexReader:汇总 TiKV 上的 IndexFullScan 或 IndexRangeScan 算子的数据。
- IndexLookup:先汇总 Build 端的 RowID,再根据这些 RowID 在 Probe 端精确读取数据。Build 端是 IndexFullScan 或 IndexRangeScan,Probe 端是 TableRowIDScan。
- IndexMerge:类似 IndexLookup,但可以同时读取多个索引的数据。先汇总所有 Build 端的 RowID,再在 Probe 端精确读取数据。
TiKV (Cop)
- TableFunScan:全表扫描。
- TableRangeScan:带有范围的表数据扫描。
- TableRowIDScan:根据上层传递的 RowID 扫描表数据。
- IndexFullScan:扫索引数据,而非表数据。
- IndexRangeScan:带有范围的索引数据扫描。
- Selection:条件过滤。
综合
- StreamAgg
- HashAgg
- IndexJoin
四、EXPLAIN 返回结果介绍
- id:算子名或执行 SQL 语句需要执行的子任务。
- estRows:TiDB 预计会处理的行数,基于字典信息、CMSketch 或直方图等统计信息估算。
- task:算子在执行语句时的所在位置。
- access-object:被访问的表、分区和索引,尤其在有组合索引时,该字段信息很有参考意义。
- operator info:访问表、分区和索引的其他信息。
五、执行计划与优化相关
Dashboard中关注SQL性能的关键点:
-
索引使用情况:
- 检查SQL查询是否使用了合适的索引。
- 识别是否存在未使用索引或错误索引的情况。
-
执行计划的有效性:
- 分析执行计划是否失效或过时。
- 确定是否需要重新生成执行计划。
-
MVCC版本与GC:
- 监控MVCC版本是否过大,可能导致性能问题。
- 检查GC(垃圾回收)是否及时清理旧版本数据。
-
集群负载情况:
- 评估当前集群的负载是否过高,可能影响SQL执行速度。
- 识别高负载时段,以便进行性能调优或资源分配。
-
TSO获取超时:
- 监控TSO(时间戳服务)获取是否超时,这可能影响事务的执行。
- 分析超时原因,如网络延迟、TSO服务负载等。
优化建议:
-
针对执行次数TOP的SQL进行优化:
- 识别执行次数最多的SQL语句,作为优化重点。
- 分析这些SQL的执行计划和性能瓶颈。
-
处理执行计划不稳定的问题:
- 重新收集统计信息,以确保执行计划的准确性。
- 考虑强制指定索引,以优化查询性能。
- 绑定执行计划,防止计划频繁变化导致的性能波动。