TiFlash 优化中常见的误区是盲目依赖列存索引或忽略存储引擎选择。为避免错误索引拖慢查询,首先应检查统计信息是否过时,使用 ANALYZE 更新。其次,注意 TiFlash 本身无索引概念,若过滤条件选择性高,应通过 Hint 强制走 TiKV 索引查询。此外,避免在索引列上使用函数或不当的 Join 方式,合理配置 Engine 隔离,并结合执行计划分析成本差异,确保优化器选择正确的执行路径,从而显著提升查询性能。
TiDB SQL 调优案例之避免 TiFlash 帮倒忙
早上收到某系统的告警 tidb 节点挂掉无法访问,情况十万火急。登录中控机查了一下 display 信息,4 个 TiDB、Prometheus、Grafana 全挂了,某台机器 hang 死无法连接,经过快速重启后集群恢复,经排查后是昨天上线的某个 SQL 导致频繁 OOM。于是开始亡羊补牢,来一波近期慢 SQL 巡检 #手动狗头#。。。随便找了一个出现频率比较高的慢 SQL,经过优化后竟然性能提升了 1500 倍以上,感觉有点东西,分享给大家。分析过程 该慢 SQL 逻辑非常简单,就是一个单表聚合查询,但是耗时达到 8s 以上,必有蹊跷。脱敏后的 SQL 如下:代码语言:javascript AI 代码解释 SELECTcast(cast(CAST(SUM(num)/COUNT(time)ASCHAR)ASDECIMAL(9,2))ASsigned)speed,--此处省略 n 个字段 FROM(SELECTDATE_FORMAT(receive_time,'%Y-%m-%d %H:%i:00')AStime,COUNT(*)ASnumFROMdb1.tableWHEREcreate_time>DATE_SUB(sysdate(),INTERVAL20MINUTE)GROUPBYtimeORDERBYtime)speed; 碰到慢 SQL 不用多想,第一步先上执行计划:很明显,这张 900 多万行的表因为创建了 TiFlash 副本,在碰到聚合运算的时候优化器选择了走列存查询,最终结果就是在 TiFlash 完成暴力全表扫描、排序、分组、计算等一系列操作,返回给 TiDB Server 时基本已经加工完成,总共耗时 8.02s。咋一看好像没啥优化空间,但仔细观察会发现一个不合理的地方。执行计划倒数第二排的 Selection 算子,也就是 SQL 里面子查询的 where 过滤,实际有效数据 1855 行,却扫描了整个表接近 950W 行,这是一个典型的适合索引加速的场景。但遗憾的是,在 TiFlash 里面并没有索引的概念,所以只能默默地走全表扫描。
错误索引的解决方案
在观察到某个查询的执行速度达不到预期时,可能是它的索引使用有误。可能造成 TiDB 优化器选择非预期索引的原因包括:统计信息过时:优化器依赖统计信息来估算查询成本。如果统计信息过时,可能导致优化器作出次优选择。统计信息不匹配:即使统计信息是最新的,也可能无法准确反映数据分布情况,导致成本估算偏差。成本计算不准确:当查询的结构复杂或数据分布不均时,优化器有可能会错误地估算使用某个索引的成本。存储引擎选择不当:在某些场景下,优化器选择的存储引擎可能不适合当前查询。函数下推限制:部分函数或操作无法下推到存储引擎执行,可能会影响查询性能。可以先使用表的健康度信息来查看统计信息的健康度。根据健康度可以分为以下两种情况处理。这意味着距离 TiDB 上次执行 ANALYZE 已经很久了。这时可以先使用 ANALYZE 命令对统计信息进行更新。更新之后如果仍在使用错误的索引,可以参考下一小节。这时意味着刚刚结束 ANALYZE 命令或者结束后不久。这时可能和 TiDB 对行数的估算逻辑有关。对于等值查询,错误索引可能是由 Count-Min Sketch 引起的。这时可以先检查是不是这种特殊情况,然后进行对应的处理。
数据库|SQL 调优案例之 TiFlash 帮倒忙该怎么办? - 墨天轮
分析过程 该慢 SQL 逻辑非常简单,就是一个单表聚合查询,但是耗时达到 8s 以上,必有蹊跷。脱敏后的 SQL 如下:SELECTAL(9,2))ASsigned ) speed, -- 此处省略 n 个字段 FROM ( SELECT DATE_FORMAT( receive_time,'%Y-%m-%d %H:%i:00')AStime, COUNT(*)ASnum FROM db1.table WHERE create_time >DATE_SUB(sysdate(),INTERVAL20MINUTE) GROUPBY time ORDERBY 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)ASCHAR)ASDECIM cast(cast(CAST(SUM(num)COUNT(time)ASCHAR)ASDECIMAL(9,2))ASsigned ) speed,
TiDB 数据库性能优化篇 (4)TiFlash 性能分析和优化方法
你可以通过 Performance Overview 面板中的 TiFlash 面板,来监控和评估 TiFlash 集群的性能。通过以下三个指标,你可以快速判断 TiFlash 集群的资源使用率:CPU:每个 TiFlash 实例的 CPU 使用率 Memory:每个 TiFlash 实例内存的使用情况 IO utilization:每个 TiFlash 实例的 IO 使用率 示例:CH-benCHmark 负载资源使用率 该 TiFlash 集群包含两个节点,每个节点配置均为 16 核、48G 内存。当 CH-benCHmark 负载运行时,CPU 利用率最高可达到 1500%,内存占用最大可达 20 GB,IO 利用率达到 91%。这表明 TiFlash 节点资源接近饱和状态。吞吐指标 通过以下指标,你可以了解 TiFlash 的吞吐情况:MPP Query count:每个 TiFlash 实例 MPP 查询数量的瞬时值,表示当前 TiFlash 实例需要处理的 MPP 查询数量 (包括正在处理的以及还没被调度到的)。Request QPS:所有 TiFlash 实例收到的 coprocessor 请求数量。run_mpp_task、dispatch_mpp_task 和 mpp_establish_conn 为 MPP 请求。batch:batch 请求数量。cop:直接通过 coprocessor 接口发送的 coprocessor 请求数量。cop_execution:正在执行的 coprocessor 请求数量。remote_read、remote_read_constructed 和 remote_read_sent 为 remote read 相关指标,remote read 增多一般意味着系统出现了问题。
FAQ
Q: TiFlash 为什么会导致查询变慢?
A: 因为 TiFlash 没有索引概念,对于高选择性过滤场景可能全表扫描。
Q: 如何强制查询走 TiKV 索引?
A: 使用 Hint 如 /*+ READ_FROM_STORAGE(TIKV[table]) */。
Q: 统计信息过时会有什么影响?
A: 导致优化器成本估算偏差,选择错误索引或引擎。