TiDB SQL性能优化:规避TiFlash的潜在问题
背景
系统监控报警显示某节点异常宕机,经检查发现4个TiDB实例及监控组件均出现故障。通过重启恢复集群后,排查确认是新上线的SQL引发频繁内存溢出。
通过分析发现某高频慢查询存在严重性能问题,优化后效率提升超1500倍,特此分享优化过程。
分析过程
定位到一个看似简单的单表聚合查询,执行耗时超过8秒。原始SQL结构如下:
SELECT
cast( cast( CAST( SUM( num ) / COUNT( time ) AS CHAR ) AS DECIMAL ( 9, 2 )) AS signed ) speed,
... -- 此处省略n个字段
FROM
(
SELECT
DATE_FORMAT( receive_time, '%Y-%m-%d %H:%i:00' ) AS time,
COUNT(*) AS num
FROM
db1.table
WHERE
create_time > DATE_SUB( sysdate(), INTERVAL 20 MINUTE )
GROUP BY
time
ORDER BY
time
) speed;
通过执行计划分析发现,由于表存在TiFlash副本,优化器选择列存扫描。虽然数据量达950万行,但实际过滤后仅1855条有效数据,这本应通过索引加速。
优化步骤:
- 验证create_time字段索引有效性,确认已建立索引
- 尝试强制使用TiKV存储:
SELECT /*+ READ_FROM_STORAGE(TIKV[db1.table]) */
...
FROM
(
SELECT /*+ READ_FROM_STORAGE(TIKV[db1.table]) */
...
FROM
db1.table
WHERE
create_time > DATE_SUB( sysdate(), INTERVAL 20 MINUTE )
GROUP BY
time
) speed;
关键知识点:hint作用域限制,需将注释放置在子查询内
调整后执行计划显示仍使用TiKV全表扫描,性能未达预期。进一步分析发现sysdate()函数导致索引失效问题。
解决方案
通过将sysdate()替换为now()函数,使优化器能准确估算时间范围,成功利用索引:
SELECT
...
FROM
(
SELECT /*+ READ_FROM_STORAGE(TIKV[db1.table]) */
...
FROM
db1.table
WHERE
create_time > DATE_SUB( now(), INTERVAL 20 MINUTE )
GROUP BY
time
) speed;
优化后执行时间从8.02秒降至4.43毫秒,性能提升1800倍。
深度思考
优化器误判可能原因:
- Selection算子估算行数与实际差异过大
- TiFlash估算机制对动态时间函数的处理缺陷
- 索引有效性评估逻辑待优化
建议:
- 优先使用静态时间函数
- 合理控制TiFlash副本使用场景
- 定期进行执行计划分析
总结
TiFlash作为列存引擎需谨慎使用,优化器决策仍需人工干预。良好SQL习惯对数据库性能至关重要,建议避免过度依赖函数表达式。