黄东旭解析 TiDB 的核心优势
714
2024-03-01
根据用户名获取该用户的某个分类下的帖子列表。
接到这个任务,看上去真的很简单,用户表关联帖子表关联帖子分类表即可查询到数据。
select title, content, type from users a, posts b, post_type c where a.id = b.user_id and b.cate_id = c.id and a.name = name1 and c.type = type1 limit 10;写完 SQL,当然要分析下 SQL 性能了。
怎么回事,索引和预期走的不一样,怎么是帖子表 b 和帖子分类表 c 先做了一次 HashJoin?
线上帖子表 b 数据很多,与分类表 c 做关联的话,那岂不是慢查询!
为什么不是用户表 a 和 帖子表 b 先做关联呢,这两个表做关联之后数据就很少了,查询应该不会慢。
尝试一下之前还没切换 TiDB 的 MySQL 测试环境,执行符合预期啊!
看起来是 TiDB 的特性嘛!论坛里搜一搜先!
这个帖子结帖信息就很相似啊,执行计划选择错误!
那来看一下 ANALYZE 的作用,为什么会导致这种情况呢?
ANALYZE 语句用于更新 TiDB 在表和索引上留下的统计信息。执行大批量更新或导入记录后,或查询执行计划不是最佳时,建议运行 ANALYZE。
当 TiDB 逐渐发现这些统计数据与预估不一致时,也会自动更新其统计数据。
看了描述,测试环境应该没有大量删除和导入,死马当活马医,对三个表执行了下 analyze,果然没有效果。
论坛继续搜了搜也没有很符合的案例,但不怕,官方文档里还有有 SQL 性能调优系列文档,一篇篇翻下来吧,应该能找到问题。
皇天不负有心人,这个 Join Reorder 算法好像有点意思。
在实际的业务场景中,多个表的 Join 语句是很常见的,而 Join 的执行效率和各个表参与 Join 的顺序有关系。
如 select * from t1, t2, t3 where t1.a=t2.a and t3.a=t2.a,这个 SQL 中可能的执行顺序有 “t1 和 t2 先做 Join,然后再和 t3 做 Join” 以及 “t2 和 t3 先做 Join,然后再和 t1 做 Join” 两种情况。根据 t1 和 t3 的数据量及数据分布,这两种执行顺序会有不同的性能表现。
因此优化器需要实现一种决定 Join 顺序的算法。目前 TiDB 中使用的算法是 Join Reorder 算法,又称贪心算法。
当前的 Join Reorder 算法存在如下限制:
受结果集的计算算法所限并不会保证一定会选到合适的 Join order
很符合我的情况,帖子分类表最小,所以会用帖子分类表 c 来去尝试和用户表 a 和帖子表 b 分别做 Join。
然后就选择了帖子表 b 和帖子分类表 c 做关联。
但因为帖子表数据量非常大,帖子分类表很小,这两个表做关联的话,关联后的结果很多。
而用户表 a 和帖子表 c 关联,可能只有几十条数据,之后再关联分类表 C 这才是一个最佳的执行路径!
既然找到了问题,那 TiDB 当然有现成的解决方案!
目前 TiDB 中支持使用 STRAIGHT_JOIN 语法来强制指定一种 Join 顺序。
STRAIGHT_JOIN() 提示优化器在生成表连接顺序时按照表名在 FROM子句中出现的顺序进行连接。
SELECT /*+ STRAIGHT_JOIN() */ * FROM t t1, t t2 WHERE t1.a = t2.a;来来来,试一下:
果然,执行结果按照顺序选择了最优执行路径,问题解决!
虽然 TiDB 支持了几乎 100% 的 M有SQL 语法,但还是会有很多由于实现、分布式等原因导致由一些独有的特性。
因此,在使用时,不能经验主义,每个 SQL 还是要老老实实在 TiDB 中执行一次,确认是否符合预期。
如果不符合预期,那也不用怕,TiDB 的论坛和文档很丰富,慢慢看,别着急,总有一款适合你的解决方案。
参考文档:
与 MySQL 兼容性对比
SQL 性能调优
ANALYZE 文档
ANALYZE TABLE 作用 - TiDB - TiDB 的问答社区 (asktug.com)
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。