在布尔字段上建立索引以删除分区表中的记录

时间:2018-08-17 05:48:15

标签: mysql performance rds

我有一个很大的MySQL表,其中可能包含1亿条记录。表的架构是这样的-

Id varchar(36), --guid,  primary key
IsDirty bit(1),
CreatedOn(Date),
Info varchar(500)

我在CreatedOn字段上创建了一个分区,该分区为月度数据创建了一个分区。表中的某些行已更新,并且isDirty设置为1。最多,只有10%的行具有IsDirty = 1。有一个进程每天晚上运行,并删除6个月大的IsDirty = 0值的数据。

如果我也在IsDirty字段上创建索引,是否还能提高性能?据我了解,在位字段上创建索引可能不会增加性能,但是在删除记录后重新建立索引可能会由于索引而降低性能。

我的理解正确吗?有没有更好的方法来实现所需的功能?

2 个答案:

答案 0 :(得分:1)

有一条经验法则说,最好是对基数较高的列进行索引。基数是该列中不同值的估计数量。当您执行show indexes from your_table;时,您会看到IsDirty列的基数为2。非常糟糕。

但是,这不考虑数据的分布。当只有10%的人拥有IsDirty = 1时,像select * from your_table where IsDirty = 1这样的查询将从索引中受益。另一方面,检查IsDirty = 0的删除作业将无益,因为仅进行全表扫描会更便宜,因为使用二级索引意味着从索引中读取主键(在每个二级索引存储了主键,因此最好使主键越小越好,以标识要读取的行。

manual给出以下有关何时首选全表扫描的信息:

  

查询每个表索引,并使用最佳索引,除非优化器认为使用表扫描更有效。一次使用扫描是基于最佳索引是否跨越了表的30%以上,但是固定百分比不再决定使用索引还是扫描。现在,优化器更加复杂,其估计基于其他因素,例如表大小,行数和I / O块大小。

还请注意,bit数据类型不适合存储值0或1。有一个bool数据类型(在内部实现为tinyint(1)。我想我已经读到了这样做的原因,但是我已经忘记了)。

答案 1 :(得分:0)

不要理会分区,它不太可能帮助提高性能。无论如何,您将需要拥有越来越多的分区并使用PARTITION BY RANGE(to_days(..))。您将无法使用DROP PARTITION,这将使删除非常快。

我将暂时收回。这个 可行,并且 may 允许DROP PARTITION,但是我对语法感到困惑。

PARTITION BY RANGE(TO_DAYS(CreatedOn))
SUBPARTITION BY LINEAR KEY(IsDirty)
SUBPARTITIONS 2

如果您每天晚上的结局都是DELETE,那么

  • 每小时执行一次(或连续执行),以免删除次数过大
  • 按照讨论的here
  • 对其进行分组

也有

INDEX(IsDirty, CreatedOn) -- in this order.

(注意:如果可以使子分区正常工作,则不需要此索引。)

其他提示:

  • 使用InnoDB。
  • innodb_buffer_pool_size设置为RAM大小的大约70%。
  • 由于访问的随机性,UUID对于大型表来说很可怕-因此I / O很高。
  • Id varchar(36), --guid, primary key-将其打包到BINARY(16)中。 (让我知道是否需要帮助。)节省空间->缩小表->减少I / O。
  • 由于uuid太多,分区 可能有助于避免大量I / O -这是因为本月所有插入内容都将进入一个分区。也就是“工作集”,因此buffer_pool的大小可以更小。