数据库|SQL调优案例之TiFlash帮倒忙该怎么办?

news2024/9/21 10:21:03

一、背景

早上收到某系统的告警tidb节点挂掉无法访问,情况十万火急。登录中控机查了一下display信息,4个TiDB、Prometheus、Grafana全挂了,某台机器hang死无法连接,经过快速重启后集群恢复,经排查后是昨天上线的某个SQL导致频繁OOM。

于是开始亡羊补牢,来一波近期慢SQL巡检 #手动狗头#。。。

随便找了一个出现频率比较高的慢SQL,经过优化后竟然性能提升了1500倍以上,感觉有点东西,分享给大家

二、分析过程

该慢SQL逻辑非常简单,就是一个单表聚合查询,但是耗时达到8s以上,必有蹊跷。

脱敏后的SQL如下:

SELECT
    cast( cast( CAST( SUM( num ) / COUNT( time ) AS CHAR ) AS DECIMAL ( 9, 2 )) AS signed ) speed,
    ... -- 此处省略n个字段
FROM
    (
    SELECT 
        DATE_FORMAT( receive_time, '%Y-%m-%d %H:%i:00' ) AS time,
        COUNT(*) AS num 
    FROM
        db1.table
    WHERE
        create_time > DATE_SUB( sysdate(), INTERVAL 20 MINUTE )
    GROUP BY
        time 
    ORDER BY
    time 
    ) speed;

碰到慢SQL不用多想,第一步先上执行计划:

​很明显,这张900多万行的表因为创建了TiFlash副本,在碰到聚合运算的时候优化器选择了走列存查询,最终结果就是在TiFlash完成暴力全表扫描、排序、分组、计算等一系列操作,返回给TiDB Server时基本已经加工完成,总共耗时8.02s。

咋一看好像没啥优化空间,但仔细观察会发现一个不合理的地方。执行计划倒数第二排的Selection算子,也就是SQL里面子查询的where过滤,实际有效数据1855行,却扫描了整个表接近950W行,这是一个典型的适合索引加速的场景。但遗憾的是,在TiFlash里面并没有索引的概念,所以只能默默地走全表扫描。

第一步,先看过滤字段是否有索引,通常来说create_time这种十有八九都建过索引,检查后发现确实有。

第二步,尝试让优化器走TiKV查询,这里直接使用hint的方式:

SELECT /*+ READ_FROM_STORAGE(TIKV[db1.table]) */
    cast( cast( CAST( SUM( num ) / COUNT( time ) AS CHAR ) AS DECIMAL ( 9, 2 )) AS signed ) speed,
    ... -- 此处省略n个字段
FROM
    (
    SELECT 
        DATE_FORMAT( receive_time, '%Y-%m-%d %H:%i:00' ) AS time,
        COUNT(*) AS num 
    FROM
        db1.table
    WHERE
        create_time > DATE_SUB( sysdate(), INTERVAL 20 MINUTE )
    GROUP BY
        time 
    ORDER BY
    time 
    ) speed;

再次生成执行计划,发现还是走了TiFlash查询。

这里就引申出一个重要知识点,关于hint作用域的问题,也就是说hint只能在指定的查询范围内生效。

具体到上面这个例子,虽然指定了db1.table走TiKV查询,但是对于它所在的查询块来说,压根不知道db1.table是谁直接就忽略掉了。

所以正确的写法是把hint写到子查询中:

SELECT
    cast( cast( CAST( SUM( num ) / COUNT( time ) AS CHAR ) AS DECIMAL ( 9, 2 )) AS signed ) speed,
    ... -- 此处省略n个字段
FROM
    (
    SELECT  /*+ READ_FROM_STORAGE(TIKV[db1.table]) */
        DATE_FORMAT( receive_time, '%Y-%m-%d %H:%i:00' ) AS time,
        COUNT(*) AS num 
    FROM
        db1.table
    WHERE
        create_time > DATE_SUB( sysdate(), INTERVAL 20 MINUTE )
    GROUP BY
        time 
    ORDER BY
    time 
    ) speed;

对应的执行计划为:

小提示:也可以通过set session tidb_isolation_read_engines = 'tidb,tikv';来让优化器走tikv查询。

发现这次虽然走了TiKV查询,但还是用的TableFullScan算子,整体时间不降反升,和我们预期的有差距。

没走索引那肯定是和查询字段有关系,分析上面SQL的逻辑,开发是想查询table表创建时间在最近20分钟的数据,用了一个sysdate()函数获取当前时间,问题就出在这。

获取当前时间常用的函数有now()和sysdate(),但这两者是有明显区别的。引用自官网的解释:

  • now()得到的是语句开始执行的时间,是一个固定值

  • sysdate()得到的是该函数实际执行的时间,是一个动态值

听起来比较饶,来个栗子一看便知:

mysql> select now(),sysdate(),sleep(3),now(),sysdate();
+---------------------+---------------------+----------+---------------------+---------------------+
| now() | sysdate() | sleep(3) | now() | sysdate() |
+---------------------+---------------------+----------+---------------------+---------------------+
| 2023-03-16 15:55:18 | 2023-03-16 15:55:18 | 0 | 2023-03-16 15:55:18 | 2023-03-16 15:55:21 |
+---------------------+---------------------+----------+---------------------+---------------------+
1 row in set (3.06 sec)

这个动态时间就意味着TiDB优化器在估算的时候并不知道它是个什么值,走索引和不走索引哪个成本更高,最终导致索引失效。

从业务上来看,这个SQL用now()和sysdate()都可以,那么就尝试改成now()看看效果:

SELECT
    cast( cast( CAST( SUM( num ) / COUNT( time ) AS CHAR ) AS DECIMAL ( 9, 2 )) AS signed ) speed,
    ... -- 此处省略n个字段
FROM
    (
    SELECT  /*+ READ_FROM_STORAGE(TIKV[db1.table]) */
        DATE_FORMAT( receive_time, '%Y-%m-%d %H:%i:00' ) AS time,
        COUNT(*) AS num 
    FROM
        db1.table
    WHERE
        create_time > DATE_SUB( now(), INTERVAL 20 MINUTE )
    GROUP BY
        time 
    ORDER BY
    time 
    ) speed;

最终结果4.43ms搞定,从8.02s到4.43ms,1800倍的提升。

滥用函数,属于是开发给自己挖的坑了。

三、解决方案

经过以上分析,优化思路已经很清晰了,甚至都是常规优化不值得专门拿出来讲,但前后效果差异太大,很适合作为一个反面教材来提醒大家认真写SQL。

其实就两点:

  1. 让优化器不要走TiFlash查询,改走TiKV,可通过hint或SQL binding解决

  2. 非必须不要使用动态时间,避免带来索引失效的问题

四、深度思考

优化完成之后,我开始思考优化器走错执行计划的原因。

在最开始的执行计划当中,优化器对Selection算子的估算值estRows和实际值actRows相差非常大,再加上本身计算和聚合比较多,这可能是导致误走TiFlash的原因之一。不清楚TiFlash的estRows计算原理是什么,如果在估算准确的情况并且索引正常的情况下会不会走TiKV呢?

另外,我还怀疑过动态时间导致优化器判断失误(认为索引失效才选择走TiFlash),但是在尝试只修改sysdate()为now()的情况下,发现依然走了TiFlash,说明这个可能性不大。

在索引字段没问题的时候,按正常逻辑来说,我觉得一个成熟的优化器应该要能够判断出这种场景走TiKV更好。

五、总结

TiFlash虽然是个好东西,但是优化器还在进化当中,难免有判断失误的时候,那么会导致适得其反的效果,我们要及时通过人工手段介入。再给TiDB优化器一些时间。

良好的SQL习惯至关重要,这也是老生常谈的问题了,再好的数据库也扛不住乱造的SQL。

版权声明:本文由神州数码云基地团队整理撰写,若转载请注明出处。

公众号搜索神州数码云基地,后台回复数据库,加入数据库技术交流群。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/536022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flink消费pubsub问题

我看网上flink消费pubsub的资料并不多,最近跑通了,大家有问题的可以给我留言。 一、基本资料 1.flink官网接入方式 Google Cloud PubSub | Apache Flink StreamExecutionEnvironment streamExecEnv StreamExecutionEnvironment.getExecutionEnviron…

Android平台如何实现外部编码后(H.264/H.265)数据实时预览播放

技术背景 我们在对接开发者的时候,遇到这样的诉求:除了正常的RTMP、RTSP直播播放外,有些硬件设备输出编码后(H.264/H.265)的数据,比如无人机或类似硬件产品,回调出来的H.264/H.265数据&#xf…

C#中的委托是什么

https://www.cnblogs.com/deepalley/p/12150931.html 1.什么是委托?(方法作另一个方法的参数) delegate void MyDel(int value); //声明委托类型 和类一样,委托是用户自定义的类型,但是类是数据和方法的集合&#…

vue实现功能完整的购物商城,商品零食、电商通用商城

目录 一、项目结构 1.项目截图 2.项目简介 3.项目布局 二、首页 1.效果图 2.源码 三、商品详情 1.效果图 2.源码 四、分类 1.效果图 五、购物车、提交订单 1.效果图 六、个人中心 1.源码结构 2、效果图 七、总结 一、项目结构 1.项目截图 2.项目简介 项目基于vue…

海睿思分享 | 一文读懂企业数据资产目录建设的重要性

小王是某公司信息化部门负责人。 某天,公司领导需要获取近三年来生产部门的人员信息全面数据,小王费了九牛二虎之力,召开了各种会议,在各个系统里来回找数据,最终找到了这些数据。然而领导所需的人员职称、人员获奖信…

UOS服务器系统配置bond

一、Bond介绍 bond可以将多个网卡绑定到一起,可以让两个或多个接口作为一个接口,同时提高带宽,并提供网络链路的冗余,当有其中一块网卡故障的时候,不会中断服务器的业务。 二、Bond模式 1、mode0(balanc…

老杨说运维 | 运维数智化转型正确打开方式是什么?他这样说

2023年5月9日,中国计算机用户协会信息科技审计分会会员大会暨金融科技风险管理与审计论坛成功于北京召开。擎创科技CEO杨辰受邀与会,并分享了在数智运维发展过程中对企业数智化转型建设的规划思考以及相关实践经验。 同时,年会上举行了“金融…

《基础知识》提示学习的基本知识

《基础知识》提示学习的基本知识 提示学习背景提示的形式和元素提示学习的输入形式提示学习的重要元素提示学习的输入形式举例基本提示任务提示学习 内容参考:打工人转型之道(二):提示工程(Prompt Engineering)进阶篇

【服务器】利用树莓派搭建 web 服务器【无需公网IP】

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 目录 概述 使用 Raspberry Pi Imager 安装 Raspberry Pi OS 设置 Apache Web 服务器 测试 web 站点 安装静态样例站点 将web站点发布到公网 安装 Cpolar内网穿透 cpolar进行tok…

基于 FPGA 的彩色图像灰度化的设计实现(image_stitche_x)

文章目录 前言一、图像合并模块的设计二、仿真文件 前言 image_stitche_x 模块:将串口接收的尺寸为 400480 大小的彩色图像与灰度化处理后的 400480 大小的图像数据以左右形式合并成一张 800*480 的图像。 提示:以下是本篇文章正文内容,下面…

AI再度升级,IT业一片哀鸿遍野:程序员真的要失业了吗?

IT人员真的要失业了吗? 随着各个大厂已经相继传来裁员,降薪,减招的消息和ChatGPT等大型AI模型可以定制化写参考代码,甚至通过外接API直接帮助操作,IT人员似乎越来越不吃香了。 其实,ChatGPT有用的不是取代…

Diango学习-用户管理系统(简单部门管理、用户管理)

目录 1、创建项目和app 1.创建项目 2.创建app 2种创建方式 注册app 2、表结构的创建 Django中的模型字段有很多种,包括但不限于: 设计表结构(Django) 在models.py文件中创建表:部门表和员工表 加入性别列&…

FL Studio21.0.3.3517完整试用版

系统要求 FL STUDIO 可以运行在任何计算机上: 支持 WINDOWS: 7, 8, 10 或者更高版本 支持 MacOS: 10.11 或更高版本 不低于 4GB 的可用硬盘空间 建议最低 4GB 内存或 更高 当然CPU 越强大,也就意味着你运行的音源和效果器越多! FL Studio是一个非常受欢迎的数…

轻松实现远程访问本地wamp服务器,无公网IP也不怕,「内网穿透」

目录 前言 1.Wamp服务器搭建 1.1 Wamp下载和安装 1.2 Wamp网页测试 2. Cpolar内网穿透的安装和注册 2.1 本地网页发布 2.2 Cpolar云端设置 2.3 Cpolar本地设置 3. 公网访问测试 4. 结语 转载自cpolar极点云的文章:无公网IP?教你在外远程访问本地…

新零售发展现状剖析

“新零售”的商业生态将涵盖网络页面、实体店面、支付终端、数据系统、物流平台和营销路径等诸多方面。 企业通过使用大数据和人工智能等先进技术升级产品的生产、流通和销售流程,重塑商业结构与生态圈,深度融合线上服务、线下体验和现代物流。将物流、…

Devexpress GridControl 内部调用外面实现的FocusedRowChanged

个人需求是网格自带的条件发生改变时(网格显示的内容会发生改变),同时需要刷新另一个网格的数据源,而另一个网格的数据源是走的这个网格的行焦点改变事件去刷新,自带的条件发生改变时并不会触发行焦点的改变 当前情况…

【HTTP协议】

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 1. HTTP协议概述 2. HTTP协议的工作过程 3.…

LabVIEWCompactRIO 开发指南21 使用TCP/IP时处理孤立套接字

LabVIEWCompactRIO 开发指南21 使用TCP/IP时处理孤立套接字 无法重新建立侦听TCP套接字是设计基于TCP/IP的应用程序时最常见的挑战之一。此症状是由终止客户端或服务器应用程序后发生的孤立套接字引起的。如果按照本节中所述的技术设计代码,则可以避免此问题。本节…

大数据拥抱云原生 HashData助力资管数字化转型

5月16日,2023国际资管科技创业者与投资者大会“资管数据处理(大模型)技术”专场在上海举行。本次大会以“资产管理 数智技术”为主题,邀请企业、高校、投资机构等各方开展产业交流与讨论,共享共创行业机遇。 酷克数据…

GPT-5: 超越人类语言的模型,你还不了解一下?

目录 一、GPT-5时代引领者 二、技术特性 1,音频和视频处理 — 更强大的多模态处理能力 2,GPT-5颠覆影视制作:重写媒体消费时代 3,为机器人提供智慧大脑 4,更强的垂直行业应用 三、回顾一下GPT5被紧急叫停&…