我有一个很大的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字段上创建索引,是否还能提高性能?据我了解,在位字段上创建索引可能不会增加性能,但是在删除记录后重新建立索引可能会由于索引而降低性能。
我的理解正确吗?有没有更好的方法来实现所需的功能?
答案 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
,那么
也有
INDEX(IsDirty, CreatedOn) -- in this order.
(注意:如果可以使子分区正常工作,则不需要此索引。)
其他提示:
innodb_buffer_pool_size
设置为RAM大小的大约70%。Id varchar(36), --guid, primary key
-将其打包到BINARY(16)
中。 (让我知道是否需要帮助。)节省空间->缩小表->减少I / O。