写点什么

MySQL 正常执行的 SQL 在 TiDB 中变慢了

  • 2022 年 7 月 11 日
  • 本文字数:1795 字

    阅读完需:约 6 分钟

作者: HHHHHHULK 原文来源:https://tidb.net/blog/23c9c2e2

前言

在测试过程中,发现有一部分在 MySQL 里执行很流畅的 SQL,放入 TiDB 中执行耗时明显变长,有些甚至都跑不出结果。


这里简单总结下,上述情况产生的原因、优化办法、以及遇到无法优化的,如何向社区提供背景资料。

情况与方案

表结构以及数据量 MySQL 和 TiDB 都是一致的,数据库所在服务器的硬件配置也差不多。

一. 统计信息问题

在我们的测试场景中,这类情况很容易出现,因为我们每次跑测试任务前,都是通过 br 去恢复数据的。

如何判断

这类问题也比较好判断,首先就是看执行计划:


explain analyze SQL;
复制代码



可以看到operator info这列里出现了stats:pseudo,这就代表 paycore_orderinfo 这张表需要重新收集下统计信息。

优化方案

重新收集该表的统计信息:


analyze table paycore_orderinfo;
复制代码


收集完统计信息后,我们再跑下 sql:



可以看到原本是扫描了 paycore_orderinfo 全表,现在用到 create_time 索引了,执行时间从 7 秒减少到 0.15 秒。


如果想一次找出所有慢查询里计信息为 pseudo 的 SQL,可以使用以下语句:


select query, query_time, stats from information_schema.slow_query where is_internal = false and stats like '%pseudo%';
复制代码

二. 优化器问题一

统计信息的问题比较常见也比较好解决,如果想要解决优化器导致执行计划偏差的问题,就需要下一定功夫了。

如何判断

因为整个 SQL 比较复杂,就截取当中的一小段,先看下这条 SQL 在 MySQL 下的执行计划:



可以看到整个 SQL 的执行计划还是较好的,运行速度也很快。


相同的 SQL 放到 TiDB 中执行,执行计划如下:



在 MySQL 里 t 表用到了 primary key,而在 TiDB 中,t 表则使用了 idx_ta_ack_2(ta_no) 这个索引,导致实际影响的行数 actRows 达到了 200 多万行,最终整个 SQL 执行失败,报错为:


[Err] 1105 - Out Of Memory Quota![conn_id=226083]
复制代码

优化方案

现在单独把这条 SQL 表关联的地方拿出来:


FROMtLEFT JOIN d ON (t.app_no = d.ack_no),eWHERE
复制代码


为了让 TiDB 优化器更好地去判断,把表关联顺序改为:


FROMeSTRAIGHT_JOIN tLEFT JOIN d ON (t.app_no = d.ack_no)WHERE
复制代码


执行计划如下:



t 表用回了 primary key,跑起来的耗时也比 MySQL 快了不少。

三. 优化器问题二

还有种情况,在 MySQL 里执行计划正常,但是在 TiDB 中表关联被转为了全表的 hashjoin。

如何判断

先看下 MySQL 中的执行计划:



TiDB 中的执行计划:



可以看到 g 表是TableFullScan,这样整个 SQL 的执行时间就变得很长。

优化方案

为了让 g 表能正常的走到索引关联,这边在 SQL 里加了 hint,加完 hint 的执行计划如下:



SQL 执行时间也恢复了正常。


因为 SQL 实在是太长,不便于放在文章展示,所以只截取了一部分。


这里想说的是,一般优化器的问题会出现很复杂、join 关系很密集的 SQL 中,处理的方式大致有三种:


  1. SQL 加 hint;

  2. 通过 binding 绑定执行计划;

  3. 更改表的的连接关系;


大家可以通过实际情况进行优化,如果还是解决不了,可以收集相关信息在社区进行提问。

四. 向社区提问

如果想向社区求助,那需要那些东西呢?

1. 问题 SQL

完整的 SQL,如果有隐私信息记得替换掉。

2. 表结构

SQL 中所有表的建表语句,以及表中所包含的索引。

3. 执行计划

通过 explain analyze 执行后输出的执行计划。


如果遇到 SQL 过大,被 kill 掉,无发跑出执行计划的情况,那可以通过 EXPLAIN FOR CONNECTION 命令获取动态的执行计划,命令如下:


EXPLAIN FOR CONNECTION ID; #ID为正在执行的SQL ID
复制代码

4. 表的统计信息

收集方式:


curl http://172.16.XXX.XXX:10080/stats/dump/schema_name/table_name > dump.txt
复制代码


收集完以上四样东西,就可以去社区发帖啦。

总结

如果遇到 MySQL 里执行的话,而在 TiDB 里跑不动的 SQL,可以按以下几个步骤去做:


  1. 仔细分析执行计划,执行计划里有足够多的信息。

  2. 遇到 pseudo,择时进行 analyze table 操作。

  3. 如果是优化器判断的问题,根据统计信息进行 sql 绑定或更改表连接方式(这个需要非常谨慎,不像加 hint,更改连接方式需要动代码,关联逻辑和结果必须得是正确的)。

  4. 收集所有相关的信息向社区求助。


个人觉得此类问题大家可以大胆向社区寻求帮助,一来可以解决自己的问题,二来也可以给官方反馈更多的实际案例。


毕竟 TiDB 目前已兼容了几乎所有的 MySQL 语法,如果 SQL 执行也能保证一致或者更优,那整个从 MySQL 迁移至 TiDB 的过程将更加丝滑,所需要的测试和验证的成本会更低。


发布于: 刚刚阅读数: 2
用户头像

TiDB 社区官网:https://tidb.net/ 2021.12.15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
MySQL正常执行的SQL在TiDB中变慢了_管理与运维_TiDB 社区干货传送门_InfoQ写作社区