单表 1000 万条数据,TDengine 助力麦当劳中国实现 PERCENTILE 秒级查询优化

简介: 今天我们为大家分享一个关于 TDengine 在 PERCENTILE 函数性能优化上的真实案例。

PERCENTILE 函数用于统计表中某列的值百分位数,某一百分位所对应数据的值就称为这一百分位的百分位数, 比如 90% 的分位数的值,代表有 90% 的数小于该分位数的值,10% 的数大于该分位数的值。0 和 100 也就相当于集合的最小值跟最大值。在具体业务中,我们经常用这一函数来衡量服务响应延迟,以最常用的 p99 为例,它衡量了 99% 的情况下能达到的最大延迟,99% 的请求都低于这个数值,即绝大多数情况下的最差情况。


今天我们为大家分享一个关于 TDengine 在 PERCENTILE 函数性能优化上的真实案例。


麦当劳中国

这一案例主角是麦当劳中国,其在运维领域用 TDengine 来存储服务器监控相关数据,目前麦当劳中国的服务器数量约 800 个,单个服务器最高时每天产生 1000 万条数据,每天服务器产生的总数据量高达 35 亿条。每个服务器的数据各存于一个子表中,每天都需进行数据统计汇总。由于麦当劳中国业务上的查询主要以 percentile 函数为主,因此这一函数的性能也是其最关注的问题。


其查询流程如下:

  • Parser 将 SQL 语句转化为抽象语法树 AST,并且通过 catalog 模块获取元数据信息进行校验。
  • Planner 通过 AST 转化为逻辑执行计划(LogicPlan), 然后经过 Optimizer 对逻辑计划进行简化、重写, filter/limit 下推等优化,将逻辑计划通过分布式计划拆分,转换为可执行的物理计划(Physical Plan)。
  • Scheduler 通过 PRC 模块将物理执行计划放到消息中,调度到各个 vnode。
  • vnode 查询线程是通过物理计划创建算子树(Operator Tree),通过执行器(Executer)从 root 节点上游算子向下执行。数据流方向则相反,从 datasink 逐级向上返回,例如,需要先从 table scan 算子在 TSDB 读取数据,然后再从 Aggregate 算子调用 Function 模块进行聚合计算。
  • 对于查询超级表时要进行分布式执行,并且需要 second stage 聚合的操作,根据物理计划(由客户端 queryPolicy 决定)在 vnode/qnode/client 再次进行聚合计算,然后再返回查询结果给客户端。


查询描述如下:

SELECT COUNT(*), AVG(duration), PERCENTILE(duration,90) as line_90, PERCENTILE(duration,95) as line_95, PERCENTILE (duration,99) as line_99, PERCENTILE (duration,99.99) as line_9999 FROM tb_0 WHERE ts >='2020-01-01 00: 00:00.00.0000' and ts <= '2020-01-02 00:00:00.000';

  • 查询内容:响应时间的百分位占比
  • 查询值 count、avg、P90、P95、P99、P99.99 固定同时查询
  • 查询对象:每个服务的子表,不对超级表进行查询
  • 查询条件:1 天的时间段左右(可变,任意时间段)
  • 并发量:个位数并发查询


麦当劳中国希望在此业务背景下,单表 1000 万条数据查询响应时间能够在秒内实现,这也是本次PERCENTILE 函数性能优化的重点。


优化过程简述

在针对整个查询以及函数的执行流程以及逻辑进行详细分析后,我们发现单独查询 1 个 PERCENTILE 耗时在 1.1s,2 个 PERCENTILE 耗时在 1.8s,3 个 PERCENTILE 在 2.5s 左右,而无论几个 PERCENTILE 执行,table scan 部分都是公共的,因此通过相减可以推断出单独一个 PERCENTILE 消耗在 AGGREGATE 以及 PROJECTION 部分的耗时,即 1 个 PERCENTILE 耗时 0.7s,2 个 1 耗时 1.4s,这个几乎是线性增长的,而 table scan 部分在 0.4s, 总体上多个 PERCENTILE 耗时就是:


table_scan_cost(0.4s) + process_cost(0.7s) * N


因为 table scan 这部分涉及到 tsdbread 的存储,因此可以优化的点在于是否可以将单个耗时减少 0.7s, 或者减少执行次数 N。由于函数实际执行时间优化起来相对困难,函数算法基本上也是业界比较成熟的算法,在不对算法优化的情况下,可能只能通过一些代码技巧来做优化。减少执行次数 N 的关键在于看多次函数执行时是否有共用的地方可以进行合并。


通过观察麦当劳中国的几个 PERCENTILE 查询,我们总结出了一个特点,它们所涉及的数据列都是同一列,数据范围都是固定的,这种情况下我们可以合并数据进行分桶的部分。通过这种优化方式执行时间变为:


table_scan_cost + process_cost * N -> table_scan_cost + process_cost * 1


这样一来,即使执行多个 PERCENTILE 时间也不会随个数线性增长,测试结果也验证了这一优化的成功性。但当前结果稳定在 1.1s 左右,加上 count 和 avg,总时间在 1.2s,仍然还未能达到麦当劳中国要求的执行时间优化到 1s 内。


最终结果

这时我们将重点放在“单个耗时减少 0.7s”上,经过分析明确了多出的 300ms 耗时主要在第一遍 table sacn 以及计算上。


麦当劳中国在查询上除了使用 PERCENTILE,还使用了其他的多个函数,比如 COUNT,AVG 等其他函数。通过日志查看具体物理计划以及执行器的逻辑,发现 PERCENTILE 对于两遍扫描以及计算是这样的:

在第一遍 main scan 时,物理计划指定 dataLoad 为 1,也就是需要实际加载数据,而不去读 sma 的值,这是因为其他函数的实际计算,以及 PERCENTILE 的第一阶段计算,都会在 main scan 执行,而很多函数的计算实际上是不能依赖 sma 的,所以为了保证大部分函数能够计算,就需要加载实际数据进行计算。对于第二遍扫描 second stage scan,PERCENTILE 函数第二个阶段的执行,需要加载实际数据去做分桶并计算最终的结果,不能使用 sma,因此 dataload 仍然是 1。


针对这种情况,因为 PERCENTILE 第一阶段可以使用 sma 加速,因此我们将执行逻辑改为下面这种方式:

也就是说,在创建计划时,检测到有 PERCENTILE 函数参与运算时,将第一遍扫表设置为 Pre Scan,并且设置 dataLoad 为 0,因此 PERCENTILE 第一阶段计算可以使用 sma, 而不是实际拉取数据。第二遍扫表则当作 Main Scan,将其他函数的计算跟 PERCENTILE 第二阶段放在一起,不影响之前的逻辑。


经过这两次优化操作,最终我们消除了多出的 300ms,加上 count、avg 函数后,查询时间在 0.8s 左右,成功帮助麦当劳中国将单表 1000 万条数据查询响应时间控制在了秒内。


写在最后

PERCENTILE 秒级查询优化对于麦当劳中国来说是一项重要的技术升级,可以帮助他们更灵活、更实时地管理和优化业务运营,也为麦当劳中国与 TDengine 的更长远合作打下了基础。希望这一优化工作的经验分享能给到你帮助,如果大家还有更多的技术问题想要交流,可以联系我们,和 TDengine 资深研发进行沟通。

目录
相关文章
|
11月前
|
缓存 关系型数据库 Java
哈啰一面:如何优化大表的查询速度?
哈啰一面:如何优化大表的查询速度?
201 1
哈啰一面:如何优化大表的查询速度?
|
5月前
|
存储 关系型数据库 分布式数据库
突破大表瓶颈|小鹏汽车使用PolarDB实现百亿级表高频更新和实时分析
PolarDB已经成为小鹏汽车应对TB级别大表标注、分析查询的&quot;利器&quot;。
突破大表瓶颈|小鹏汽车使用PolarDB实现百亿级表高频更新和实时分析
|
4月前
|
存储 关系型数据库 分布式数据库
|
6月前
|
关系型数据库 分布式数据库 数据库
PolarDB-X助攻《香肠派对》百亿好友关系实现毫秒级查询
云原生数据库PolarDB分布式版(PolarDB for Xscale,简称PolarDB-X)有极强的线性扩展能力,能够多写多读;它的全局索引能力,是分布式改造的利器,成功解决了传统分布式方案中多维度查询的难题,在《香肠派对》的好友系统上,实现了百亿好友关系20万QPS的毫秒级查询。
PolarDB-X助攻《香肠派对》百亿好友关系实现毫秒级查询
|
5月前
|
存储 缓存 测试技术
现代化实时数仓 SelectDB 再次登顶 ClickBench 全球数据库分析性能排行榜!
近日,在 ClickHouse 发起的分析型数据库性能测试排行榜 ClickBench(https://benchmark.clickhouse.com/)中,现代化实时数仓 SelectDB 时隔两年后再次登顶,在全部近百款数据库和数十种机型中,性能表现位居总榜第一!
174 1
|
6月前
|
OLAP 数据处理 Apache
众安保险 CDP 平台:借助阿里云数据库 SelectDB 版内核 Apache Doris 打破数据孤岛,人群圈选提速4倍
众安保险在CDP(Customer Data Platform,客户数据平台)建设中,通过引入阿里云数据库SelectDB版内核Apache Doris,成功打破了数据孤岛,并显著提升了人群圈选的速度
279 1
|
存储 监控 关系型数据库
传统库分表麻烦查询慢?TDengine 如何解决“搜狐基金”的应用难题
搜狐基金团队使用的 MySQL 数据库在面对海量数据时存在能力瓶颈,在此背景下,其决定基于 TDengine 尝试一下全新的方案。
135 0
|
Cloud Native 架构师 关系型数据库
天弘基金引入阿里云瑶池数据库,实现百亿级数据处理和分析
天弘基金采用AnalyticDB云原生实时数据仓库后,实现了此前架构无法完成的百亿级数据实时处理与分析,逐步从数据支持业务升级到数据驱动业务
|
SQL 关系型数据库 MySQL
线上千万级大表排序:优化攻略揭秘,轻松应对海量数据!
前段时间应急群有客服反馈,会员管理功能无法按到店时间、到店次数、消费金额 进行排序。经过排查发现是Sql执行效率低,并且索引效率低下。遇到这样的情况我们该如何处理呢?今天我们聊一聊Mysql大表查询优化。
线上千万级大表排序:优化攻略揭秘,轻松应对海量数据!
|
SQL 人工智能 NoSQL
持续九年,国际排名第一的宽表数据库概述|学习笔记
快速学习持续九年,国际排名第一的宽表数据库概述
176 0
持续九年,国际排名第一的宽表数据库概述|学习笔记