{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/tiflash-is-getting-faster",
    "result": {"pageContext":{"blog":{"id":"Blogs_18","title":"为啥 TiFlash 又变快了？丨TiDB 工具","tags":["TiFlash"],"category":{"name":"产品技术解读"},"summary":"短短几周时间，每次 TiFlash 的版本更新都会带来新的性能的改进，速度越来越快","body":"[TiFlash](https://pingcap.com/blog-cn/#TiFlash) 这个项目的核心思路保持了 TiDB 家族一贯的风格：持续听取用户反馈、持续改进、持续优化、高速迭代。最近几周陆续有数十家用户已经率先体验了 TiFlash，测试的过程中很多同学注意到一个现象，**短短几周时间，每次 TiFlash 的版本更新都会带来新的性能的改进，速度越来越快**，也会问到 TiFlash 越来越快的原理，所以就有了这篇深度解析。\n\n## TiFlash 加速之谜\n\nTiFlash 诚然本质是依靠列存加速，但它也借助了 ClickHouse 计算层的优异实现，因此它也不仅仅是列存。TiFlash 与 TiKV 一样，拥有协处理机制。简单来说，协处理器就是替 TiDB 分担计算的机制。下面我们看下这个例子：\n\n```sql\nSELECT COUNT(*) FROM LINEORDER;\n```\n\n![](https://img1.www.pingcap.com/prod/1_count_order_lineorder_00af72ad37.png)\n\n看这样一个简单的 `count` 计算的执行计划，其中 operator info 栏目中 `count(1)` 的被标记为 `cop[tiflash]`，这表示 TiFlash 将会执行 Hash 聚合计算 `count(1)`，而实际需要返回给 TiDB 的数据，仅仅是聚合完之后的结果，在大多数场景下，返回的数据将会非常少。这种协处理器机制，将会由各个 TiFlash 按照 Region（数据分片）为单位分布式执行。由于 TiFlash 配备了优异的计算模块，因此这部分下推优化是 TiFlash 加速的关键因素之一。\n\n**这里就有一个关键因素：并不是所有计算都可以完全下推到 TiFlash 进行加速。**\n\n## 哪些计算无法加速？\n\n如果有函数在 TiFlash 没有实现，那么它将阻碍计算加速。\n\n让我们看下这样一个查询：\n\n```sql\nSELECT COUNT(*) FROM LINEORDER WHERE DATE_FORMAT(LO_ORDERDATE, “%Y”) >= ‘1998’;\n```\n\n![](https://img1.www.pingcap.com/prod/2_count_order_date_a616494623.png)\n\n![](https://img1.www.pingcap.com/prod/3_order_result_ab8da94dce.png)\n\n上面的执行计划中，TiFlash 只承担 `TableFullScan` 也就是扫表部分，而 `count(1)` 却并没有在 TiFlash 中执行。这是为何？其实原因也很简单：因为暂时 `date_format` 函数在 TiFlash 中并没有实现，因此从谓词过滤以及所有之后的计算都将无法加速。这也许会带来几倍甚至十几倍的速度差距。\n所以遇到这样的情况该怎么办？你可以很简单改写为：\n\n```sql\nSELECT COUNT(*) FROM LINEORDER WHERE LO_ORDERDATE >= ‘1998-01-01’;\n```\n\n![](https://img1.www.pingcap.com/prod/4_count_orderdate_eee072a45c.png)\n\n**改完这个查询从将近 5 分钟加速到 1.61 秒。**\n\n不过这并不是我们在这里希望你默默忍受的。**我们希望你联系我们，告诉我们这里下推不知道为什么不工作了，我们会帮你分析，如果有缺漏的下推，我们会迅速补上**。\n\n## Super Batch 优化\n\n有用户反映，当 Region 数量非常多的时候，TiFlash 的加速会放缓。这是由于当 Region 过多时，TiDB 会产生数量大量的 Region 读取请求，而造成调度延迟放大。这个效果有些类似 Hadoop 上小文件过多而造成的性能影响。我们之前给出的建议是，打开 Region Merge，并在可能的情况下将 Region 大小调至 192M 而非默认的 96M。但就算这样，仍然可能有超大表包含数千甚至上万 Region 数让性能下降。\n\n**对于这样的问题，近期我们推出了 Super Batch 优化，当开启优化时，TiDB 将会把所有需要发送到同一个 TiFlash 的请求合并，而 TiFlash 则会在内部自行进行 Raft 相关的读取容错。**\n\n通过这样的方式，TiFlash 不再对 Region 大小敏感。如下是 ontime 数据集的测试对比。\n\n![](https://img1.www.pingcap.com/prod/5_cop_super_batch_e50c7b5583.png)\n\n**如上测试结果可以看出，多数查询有接近一倍的提速，而这只是在较小数据量下（10 亿规模以内）的结果，如果数据量进一步增加，加速效果将更为显著。**\n\n## JOIN 加速\n\n有一些测试的朋友告诉我们，他的分析计算是星型模型，有不少 JOIN，执行起来似乎没有变多快。是的，以协处理器的模型，对 JOIN 类计算并不能很好加速，因为 JOIN 无法在这个框架下分担计算，进而都必须由 TiDB Server 独立承担。TiDB Server 目前并不是 MPP 架构，所以 JOIN 计算还是在单机上计算。\n\n![](https://img1.www.pingcap.com/prod/6_join_698a7b5dfa.png)\n\n那是否这样的场景就无法优化了呢？\n\n只要有足够多的的用户呼声，我们就会开动脑筋 :)\n\n**经过一番努力，现在 TiFlash 实现了针对星型模型 JOIN 的优化方案：类 Broadcast JOIN。**\n\n通过将小表 Build Hash 动作在 TiFlash 中实现，我们得以将整个 JOIN 操作下推并分布式化，这个优化不止让 JOIN 本身得以在 TiFlash 中分布式计算，而且也让后续操作例如聚合等，都可以完整下推到 TiFlash。\n\n![](https://img1.www.pingcap.com/prod/7_broadcast_join_20dc2458ec.png)\n\n而这个优化的加速效果也相当明显。我们针对标准的 Star Schema Benchmark 进行了测试，结果如下。\n\n![](https://img1.www.pingcap.com/prod/8_star_schema_benchmark_scale_100_a8ced98d79.png)\n\n总共 13 条 SQL，大家可以在 [这里](https://github.com/pingcap/tidb-bench/tree/master/ssb) 找到。**大部分查询都有明显加速，其中 6 个甚至有数量级（最多 44 倍）的加速**。\n\n相信在完整的 MPP 实现之前，这样的设计也可以满足很多用户的需求。而有些场景用不上这个优化，比如大量的大表 JOIN，则可以直接用 TiSpark。\n\n## 更多沟通，更多加速\n\n上述各个优化，都是由用户反馈而做出的针对性优化。我们也会不断快速迭代，快速演进。但是这一切的前提都是，你的使用和反馈。与我们联系，尝试 TiFlash，在解决你问题的同时，也能与我们一起打造真正符合大家需求的产品，毕竟，TiDB 是一个以社区为本的产品。社区的前进，离不开每个用户。\n\n## 欢迎体验\n\nTiDB 4.0 可以使用全新的 [TiUP](https://tiup.io/) 进行部署。大家可以使用两条命令单机部署体验或者参考 [官网文档](https://pingcap.com/docs-cn/dev/reference/tiflash/deploy/#%E5%85%A8%E6%96%B0%E9%83%A8%E7%BD%B2-tiflash) 部署集群。\n\n```\ncurl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh \ntiup playgroud\n```\n\n*注：部分上述优化还未包含在 4.0 RC，请与我们联系参与体验。另，TiFlash 部署暂时只支持 Linux 环境。*","date":"2020-04-22","author":"马晓宇","fillInMethod":"writeDirectly","customUrl":"tiflash-is-getting-faster","file":null,"relatedBlogs":[]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}