如何避免索引带来的写热点问题

【 TiDB 使用环境】生产环境 /测试/ Poc
【 TiDB 版本】6.5
【复现路径】表数据含有约50列,50亿左右的数据,日增数据约1000万,目前通过日期索引来获取每天数据,未使用tiflash
【遇到的问题:问题现象及影响】索引前缀为日期,导致出现写热点,监控和日志中大量出现 region miss、region scheduling警告

请问通过分区表来代替日期索引是否可以解决这个问题?或者有没有什么其它方案?

可以参考一下这里。个人觉得分区也不能解决热点问题,分区会带来分区表热点。
https://docs.pingcap.com/zh/tidb/stable/troubleshoot-hot-spot-issues#tidb-热点问题处理

1 个赞
  1. 索引优化
  • 多列复合索引:除了日期字段,你可以尝试在索引中加入其他列(如设备ID、用户ID等),这样可以避免单纯通过日期索引引发的写热点。
  • 覆盖索引:确保查询所需的字段都在索引中,可以减少访问表的次数,从而减轻读写压力。
  1. TiFlash 引擎: TiDB 6.x 版本支持 TiFlash 引擎,适用于一些读密集型的查询。通过 TiFlash 可以将部分热点数据的读取负载卸载到 TiFlash 节点,从而缓解 TiKV 的压力,减少 region missregion scheduling 的发生。如果你的应用场景中有大量的读操作,可以考虑开启 TiFlash 并将适当的表或列通过 TiFlash 存储。
  2. 调整 TiDB 配置
  • 修改 region size:可以调整 TiKV 的 region-max-size 配置项,控制每个 region 的大小。如果 region 太大,可能会造成调度和热点问题。
  • 调整 PD 的调度策略:通过优化 PD(Placement Driver)的调度策略,确保 TiDB 集群内的 region 分布更加均匀,从而避免单点热点。
  1. 水平扩展: 如果当前集群的节点较少,可以考虑通过增加 TiDB 或 TiKV 节点来水平扩展集群容量和处理能力,从而缓解由于资源不足引起的 region miss 和调度延迟问题。
1 个赞

可以按照表的某个纬度hash分区么? 例如:user_id % 1024这种?

带上业务属性,比如类别,地区,国家 等等,这些信息在加上时间就一般会比较容易打散了

打个比方:zh_wh_20250107 ,国家 + 城市 + 时间

2 个赞

但是这种索引热点,你通过增加其他字段变成组合索引,热点是打散了,但是使用起来,效率也差了呀。。。。

日期分区表解决不了这个问题 region miss、region scheduling等如果不影响业务,无视掉就好

1 个赞

每天开始的时候 pre split 一下可能可以好一点,但也需要主键的分布是比较均匀的,https://docs.pingcap.com/zh/tidb/stable/sql-statement-split-region

2 个赞

日期索引每天的增量范围是可预期的,这个预分裂的做法还是真是一个不错的方案。

1 个赞

split一下索引可能会有效果

1 个赞

日期列做hash或key分区可以打散热点,对范围读性能可能有影响。

1 个赞

分区表稳定吗?

这种即使使用分区表也依然会存在热快问题,建议可以考虑一下用hash索引

1 个赞

1.可以通过分区表解决,将表按照日期进行分区,使得不同日期的数据分布在不同的物理分区上。
2. 前缀索引优化, 虽然目前使用日期作为索引前缀导致写热点,但可以优化索引设计。例如,在日期前缀的基础上,增加一个随机或分布式的字段作为索引的一部分,使得写入操作分散。例如,假设表中有一个 user_id字段,可以创建复合索引 (date_column, user_id)。这样在相同日期下,数据会根据 user_id 分散到不同的 Region。另外再检查检查是否有不必要的索引。
3.调整一些参数配置, tikv.region-split-size适当减小该值,可以使 Region 分裂得更频繁,从而更快地分散热点数据。 tikv.region-max-size设置这个避免单个 Region 过大而成为热点, tikv.scheduler-worker-pool-size 适当增加该值,可以加快调度速度。
4. 建议使用TiFlash,它是TiDB 的列式存储引擎,主要用于加速分析型查询,减轻承载写操作的压力,也有助于分散读负载。

希望能帮到您 。

3 个赞

回答很全面啊! :rofl:

2 个赞

可以试试结合下面两种方案

使用分区表

  1. 数据分布均衡:分区表可以将数据分散到多个分区中,从而平衡写入负载,避免单个Region或节点承受过多压力。这有助于减少写入热点的发生。
  2. 选择合适的分区类型:根据数据特性和访问模式选择合适的分区类型(如范围分区、哈希分区等)。例如,哈希分区可以将数据均匀分布,适合高写入负载场景。
  3. 预分裂Region:在创建表时,使用预分裂功能将表预先分裂成多个Region,并分散到不同的TiKV节点上,提前避免热点问题。

优化索引

  1. 识别热点:使用 TiDB Dashboard的 Key Visualizer功 能识别热点区域,针对性地进行优化。
  2. 优化索引结构
  • TIDB_SHARD函数:在索引中使用TIDB_SHARD()函数创建分片索引,将热点分散到多个区域。

参考资料

https://github.com/pingcap/tidb/issues/31040
https://docs.pingcap.com/zh/tidb/stable/troubleshoot-hot-spot-issues

1 个赞

谢谢分享

感谢各位分享,预分区这个我之前有尝试过,当时我们用的还是自增主键表,主要是想解决auto_increment的问题,当时测试的结果不是很显著所以后面就没再试。但后来知道索引也会有热点问题也没有再尝试对索引预分区,印象里索引也是支持预分区来着?我回头再试试,这个用起来的话说实话比较繁琐,因为直接干涉调度而且还得根据实际的数据来手动分区,需要提供许多本来不需要考虑的数据

1 个赞

这个我也有想过,但是问题在于我没法很好量化这个操作的得失,道理上确实这么个索引法的话索引本身的写入应该是没有热点了,但是这个写入数据量的增加还有使用时的效率会有多大影响不知道怎么评估

倒不是想解决这个跳告警日志的问题,我现在的场景是想尽可能地优化写入速度,从现状来看因为kv没有报过write stall,磁盘也没有出现写延迟变高的情况,但是插入性能就是上不去,对于这个表宽度来说大概只能有1-2万条每秒