布尔字段索引以删除分区 table 中的记录

Index on Boolean field to delete records in a partitioned table

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

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

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

如果我也在 IsDirty 字段上创建索引,是否会提高性能?据我所知,在位字段上创建索引可能不会增加太多性能,但删除记录后重新索引可能会因索引而降低性能。

我的理解对吗?是否有更好的方法来实现所需的功能?

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

不过这并没有考虑数据的分布。当只有 10% 有 IsDirty = 1 时,像 select * from your_table where IsDirty = 1 这样的查询将从索引中受益。另一方面,检查 IsDirty = 0 的删除作业不会受益,因为简单地进行完整的 table 扫描会更便宜,因为使用二级索引意味着从索引中可以得到主键读取(在每个二级索引中存储主键,因此使主键尽可能小总是好的)来标识要读取的行。

manual 说明了何时首选完整 table 扫描:

Each table index is queried, and the best index is used unless the optimizer believes that it is more efficient to use a table scan. At one time, a scan was used based on whether the best index spanned more than 30% of the table, but a fixed percentage no longer determines the choice between using an index or a scan. The optimizer now is more complex and bases its estimate on additional factors such as table size, number of rows, and I/O block size.

另请注意,位数据类型不适合存储值 0 或 1。有一个 bool 数据类型(在内部实现为 tinyint(1))。我想我已经在某处读到一个原因,但我忘记了)。

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

我会暂时收回。 可能有效,可能允许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 对于大型 tables 是可怕的——因此很高 I/O。
  • Id varchar(36), --guid, primary key -- 打包成BINARY(16)。 (如果您需要帮助,请告诉我。)节省 space --> 收缩 table --> 削减 I/O.
  • 由于 uuid 的可怕性,分区 可能 有助于避免很多 I/O -- 这是因为本月的所有插入内容都将进入一个分区。也就是说,"working set",因此 buffer_pool 大小可以更小。