01
麦当劳中国
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 函数性能优化的重点。
02
优化过程简述
在针对整个查询以及函数的执行流程以及逻辑进行详细分析后,我们发现单独查询 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 内。
03
最终结果
在第一遍 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 万条数据查询响应时间控制在了秒内。
04
写在最后
PERCENTILE 秒级查询优化对于麦当劳中国来说是一项重要的技术升级,可以帮助他们更灵活、更实时地管理和优化业务运营,也为麦当劳中国与 TDengine 的更长远合作打下了基础。希望这一优化工作的经验分享能给到你帮助,如果大家还有更多的技术问题想要交流,可以添加小Tvx:tdengine,和 TDengine 资深研发进行沟通。
活动推荐
很多用户对于如何快速、便捷呈现工业现场的实时时序数据比较畏惧,觉得需要耗费大量人力进行应用开发才能实现,影响了时序数据快速有效的利用。
其实,和IT运维采用 Telegraf + TDengine + Grafana 一样,工业物联网可以非常方便地利用 TDengine Enterprise/Cloud OPC 接入能力,通过搭建 OPC + TDengine + Grafana 方案,快速实现低代码的业务数据监控。
2023 年 10月 19 日(周四) 19:30,TDengine 行业产品经理肖波介绍《以烟草行业为例,聊聊如何基于 PLC + OPC + TDengine,快速搭建工业生产监测系统》。感兴趣的小伙伴,点击下方视频号卡片,预约观看。
往
期
推
荐
本文分享自微信公众号 - TDengine(taosdata_news)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。