TiDB 4.0 新特性前瞻(三)再也不用担心我的 SQL 突然变慢了
关系型数据库的 DBA 日常肯定遇到过这样的一种场景:SQL 执行计划选择错误,这类问题的危害是很大的,常常导致业务突然卡顿,数据库过载等不良后果。
举个例子,假设我们有这么一张表:
其中,姓名和性别这两列有索引。我们设想一下,在这张表上,我们进行下面一条查询:
SELECT * FROM t WHERE 姓名='小明' and 性别='男'
正常情况下,SQL 优化器内部会通过采样等手段,得到姓名和性别这两个索引的数据区分度,在这个场景下,大多数时候,「姓名」都是一个更有区分度的索引,所以优化器会选择姓名进行查询就能过滤掉大量的行。
但是,我们设想一个比较极端的情况,突然这个表中写入了大量的“女性小明”:
也就是会出现这样一种情况:对这条语句来说,使用「姓名」这个索引区分度变得不高,因为有大量的同名小明,但是「性别」这个索引却非常合适(只有一个男性小明)。
如果这个时候 SQL 优化器仍然选择了姓名的索引,在业务中就会出现一条本来跑得好好的 SQL 突然变成了慢查询。
由于 TiDB 作为一个关系型数据库,而且优化器也是基于代价的优化器,通常基于代价的优化器对于数据的采样很难做到瞬时,尤其是数据量特别大表来说,总是有可能出现数据的分布随着业务的变化发生突变,即时采样做到实时,不仅仅是索引的选择,也包括 JOIN 方式的选择,JOIN 的顺序等,很难保证 100% 的情况都选对。根据我们的观察,大多数生产环境中的 SQL 问题都是由于这个原因产生的。
知道了问题的根源,解决起来也比较简单了,DBA 经常做的事情:找到慢查询,使用给语句加 hint 之类的方式(给查询语句写注释),告诉优化器:不要自己猜,我这边更了解我的业务特征,就按我告诉你的这么查。
但是通过 hint 的方式,也有以下的几个问题:
-
这些 SQL 可能不一定是手写的,可能是 ORM 之类的数据库框架生成的,修改 SQL 不现实。
-
即使改写了业务层的 SQL,相当于修改了业务代码,必然需要重新部署业务,这个可能会带来不确定的风险。
-
虽然有 hint,但是如果后期数据分布发生了变化,即使优化器知道存在更好的查询计划,但是优化器也没有办法覆盖原先的 hint。
因为有上面的问题存在,我们在 TiDB 4.0 中引入了一套全新的机制:SQL Plan Management(SPM) 帮助 DBA 解决这个问题。
我们先看看怎么用,还是上面那个例子,DBA 只需要在数据库中执行下面一条语句:
CREATE GLOBAL BINDING FOR SELECT * FROM t WHERE 姓名='小明' and 性别='男' USING SELECT * FROM t USE INDEX(性别) WHERE 姓名='小明' and 性别='男'
其实很简单,我们引入了一个新的语法叫做,CREATE BINDING FOR …(语句) USING …(语句2) 来给一类 SQL 查询绑定执行计划。
像上面通过 SPM 来修正执行计划比起 hint 的方式来说,最明显的区别就是:不需要修改业务的代码,可以由 DBA 直接实时操作数据库系统表完成且实时生效,避免了重新上线业务的麻烦。
但我们回头看一下,上面列出的问题 3 似乎没解决,如果 SQL 优化器发现了更好的执行计划,例如上面的例子,后来发现数据分布又变化了,选择「姓名」又是一个更好的方案了,且这个执行计划并没有在绑定列表中怎么办?这个问题在 TiDB 4.0 的 SPM 里面,我们通过一个叫「计划演进」的机制,很好的解决了这个问题。
顾名思义,「演进」指的就是自主的发展、进化。TiDB 4.0 的 SPM 会在设置的业务低峰时间段里抽取一小部分资源,在后台尝试其他的执行计划,如果探测出更好的执行计划,那么,SPM 会将这个新的计划加入绑定列表,下次正常的查询,TiDB 也会将这个新计划考虑在内。
计划演进功能,目前需要通过执行下面的 SQL语句,设置一个全局开关开启:
SQL> SET GLOBAL tidb_evolve_plan_baselines = on;
总的来说,SPM 功能使得用户可以对 SQL 执行计划有比较大的控制,同时又提供了灵活演进的方法,对线上执行计划的稳定性有很大帮助,相信能让 DBA 在使用 TiDB 的过程中更加安心。大家目前可以在 4.0.0 beta 中体验该功能,如果需要了解更多,请查看 相关的文档。在 TiDB 社区伙伴们合写的开源电子书《TiDB in Action》中也有 相关章节 介绍。欢迎大家试用并提出宝贵意见 info@pingcap.com。
延展阅读
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
为什么我们要从 MySQL 迁移到 TiDB?
本文转载自公众号 51CTO技术栈。 作者介绍:贺磊,360 数据库运维资深工程师,《MongoDB 运维实战作者》,知名论坛 MySQL 版主,51CTO 博客之星,闲暇之余,喜欢将部分案例写成博客,累计访问量过百万。 我先说几个最让你兴奋和开心的点吧: 在 TiDB 里,你完全不用担心磁盘容量的问题。 在 TiDB 里,原生支持 Online DDL,你完全不用担心第三方改表工具改表出现各种 Bug 的问题,相信用开源工具改过上 T 级别表的同学都遇到过或多或少的各类 error。 在 TiDB 里,加列、主键扩容字段都是秒级的,比如我刚刚就刚对一张 19 亿的表加完了字段,1 秒完事,这在 MySQL 里要 8.0 才可以,而且还要求列在最后才行。 在 TiDB 里,你会发现 count(*) 惊人的快,一张近 20 亿的表 coun(*) 大概在 1 分钟完事儿,当然,这取决于你的 KV 数量和磁盘性能。 在 TiDB 里,从 MySQL 迁移将变得简单,图形化一键迁移,爽不爽? 在 TiDB 里,绝大多数情况你会发现比单机 MySQL 有更好的性能,当然也不排除一些例外,例如...
- 下一篇
图解kubernetes批处理Job控制器的关键设计
K8s中的批处理任务模块主要是由Job控制器完成,今天我们就来关注下其底层的关键设计,包括完成状态、并行模式、并行策略等关键机制 1. 基础概念 在聊k8s的任务模块的实现的时候,我们先看一下传统的任务系统的设计与实现,然后聊下基于k8s的基础的概念 1.1 传统的任务系统设计 传统的任务系统设计主要可以分为master(任务分配/故障感知/负载均衡)、Worker(任务执行/任务监控/任务管理)、分布式协调(etcd等存储元数据)、任务仓库(存储任务的实现比如类或者接口)等几部分, 从大的部分又可以切分为两个部分管控端(分布式协调/master/仓库)、执行端(Worker),传统的任务系统大概就是这样 通常复杂的就是如何在master如何做任务的负载均衡、任务的快速完成、依赖等管控功能,其次就是如何在worker端实现一个牛x的引擎,可以支持各种不同任务的执行环境和类型的执行 1.2 基于Pod的任务载体 k8s中的最小单元调度是Pod,同样的job控制器调度的最小单元也是Pod, Pod里面包含容器,以容器为载体k8s屏蔽了传统worker模块的任务执行环境与实现两个部分,只需要...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Mario游戏-低调大师作品
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Hadoop3单机部署,实现最简伪集群
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker使用Oracle官方镜像安装(12C,18C,19C)