删除 Mysql 后对索引 table 性能的影响

Impact on performance on an Indexed table after deletion Mysql

我有一个包含 100 亿行的 table,我的搜索查询提取了 150 万行已编入索引。我的问题是,如果我删除不必要的行并减少到 300 万行,我想我的搜索条件性能会提高。这是我的问题

  1. 如果我使用 100 亿行和 300 万行查询相同数量的数据,索引如何工作

这是我的 Table 详细信息和简单的搜索查询。 @startdate 是一个输入,它总是一个月

CREATE TABLE `ABCD` (
  `ID` bigint(20) NOT NULL AUTO_INCREMENT,
  `VAL` varchar(255) DEFAULT NULL,
  `NVAL` varchar(255) DEFAULT NULL,
  `DOC` bigint(20) NOT NULL,
  `DESC` int(11) NOT NULL,
  `DateCreat` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`ID`),   
  KEY `IDX_DOC` (`DOC`), -- BTREE NON-UNIQUE
  KEY `INDEX_DESC` (`DESC`), -- BTREE NON-UNIQUE
  KEY `INDEX_DateCreat` (`DateCreat`) -- BTREE NON-UNIQUE
) ENGINE=InnoDB AUTO_INCREMENT=14755842749 DEFAULT CHARSET=utf8


SELECT  
     MONTH(@START_DATE) 'Month'
     ,count(distinct  DOC) 'Docs'

FROM 
    ABCD USE INDEX (IDX_DOC, INDEX_DateCreat)
WHERE
    DateCreat >= @START_DATE and DateCreat < @END_DATE

(评论太长了。)

视情况而定。在某些情况下不会有任何改善;在某些方面,会有显着改善。

请提供 SHOW CREATE TABLE 和样本 DELETESELECT

'search' 是如何完成的 -- 通过 PRIMARY KEY?副键?非索引列?

删除的行是否在 table 的一个“末端”(例如清除“旧”数据)?还是分散?

您如何处理返回的 150 万行? (很多!)

索引是如何工作的。从阅读维基百科中的 B+ 树开始。或者您正在使用 FULLTEXT?或者 SPATIAL?

加速

你不想 GROUP BY MONTH(DateCreat)SELECT MONTH(DateCreat) 吗?还是您真的要显示一系列月份,但仅将它们标记为一个月?

无论如何,如果你有一个摘要 table——也许是一天——你可以非常有效地总结摘要 table 中的计数以非常快速地获取 COUNT .

重新索引

我仍然需要知道您是要删除“旧”行还是分散在 'months' 中的行。

如果您要删除“旧”行,那么 PARTITIONing 会更有效率。更多详情:http://mysql.rjweb.org/doc.php/partitionmaint

如果您要删除分散在 table 中的行,让我们进入 BTrees。数据将按 PK 排序。那是 id,这可能是按时间顺序排列的(或至少大约如此)。

数据存储在块中,每个块可能有 100 行,如果这些 varchars 包含“短”字符串,则可能更多。一个块是16KB.

当您删除 scattered 行时,您将减少某些块中的行数,但不会减少块数。 (OK,如果相邻的两个block足够稀疏,就合并在一起。)

查询的速度达到巨大 table(太大而无法缓存在 ram 中)主要取决于 接触的数量。

所以,DELETE 对这个查询的性能没有多大帮助。

更好的指数

对于这个查询,将INDEX(doc)替换为INDEX(doc, date_creat) INDEX(date_creat)替换为INDEX(date_creat, doc) 会加速查询,甚至在任何删除之前。 (两个索引都可以改,但是可能会花很长时间。)

每个二级索引都是一个BTree。这个 BTree 可能会发生类似于我上面提到的删除过程中的变化。也就是说,删除一些文档可能会从第一个索引中删除块,或者删除“旧”行很可能会删除第二个索引的一大块。同时,另一个索引的密度将大大降低。

那些建议的索引正在“覆盖”。这意味着可以使用 onlyINDEX.

来执行查询

指数效率

我不得不再次说“这取决于”...

根据经验,如果要使用超过 20% 的索引,则将忽略该索引。也就是说,如果 WHERE DateCreat >= @START_DATE and DateCreat < @END_DATE 是一个 日期范围,则将考虑以 DateCreat 开头的任何索引 。对于大范围,将忽略索引并使用 table。

最佳总结

更大的日期范围:INDEX(date_creat, doc) -- 过滤将发生覆盖。没有它,将扫描整个 table;在这种情况下,table 中的块数很关键——因此,回到删除所做或未做的事情。

较小的日期范围:INDEX(date_creat, doc) 最好,但 ``INDEX(date_creat)` 次之。 Delete 影响较小,但现在需要在 BTree(数据和索引)中都考虑影响。