MySQL索引维护


12

我做了很多有关如何在MySQL中维护索引以防止碎片并以某种方式优化查询执行的研究。

我熟悉该公式,该公式可计算表的最大可用空间与数据和索引使用的空间之间的比率。

但是我的主要问题仍然没有答案。也许这是由于我熟悉SQL Server中的索引维护,并且我倾向于认为在MySQL中它应该在某种程度上相似。

在SQL Server中,您可以具有多个索引,并且每个索引可以具有不同级别的碎片。然后,您可以选择一个并在该特定索引中执行“ REORGANIZE”或“ REBUILD”操作,而不会影响其余的索引。

据我所知,没有这种“表碎片”,并且SQL Server没有提供任何工具来修复“表碎片”。它确实提供了检查索引碎片的工具(可以理解为索引碎片使用的工具,例如索引所使用的页数与该页的填充度和连续性之间的比率),以及内部和外部碎片。

至少对于我来说,所有这些都是很容易理解的。

现在,当轮到在MySQL中维护索引时,如上所述,仅存在“表碎片”的概念。

MySQL中的一个表可以有多个索引,但是当我用那个著名的公式检查“碎片率”时,我看不到每个索引的碎片,而是整个表。

当我想优化MySQL中的索引时,我不选择要操作的特定索引(如SQL Server中一样)。相反,我在整个表中执行“ OPTIMIZE”操作,这大概会影响所有索引。

当在MySQL中优化表时,数据+索引使用的空间与整个空间之间的比率将减小,这表明硬盘驱动器中进行了某种物理重组,这意味着物理空间的减少。但是,索引碎片不仅与物理空间有关,而且与由于插入和更新而随时间变化的树的结构有关。

最后,我在InnoDB / MySQL中得到了一个表。该表具有300万条记录,105列和55个索引。它是1.5GB(不包括索引),后者是2.1GB。

每天都要对该表进行数千次点击以进行更新和插入(实际上,我们并未删除记录)。

该表已经创建多年,我可以肯定没有人维护索引。

我原本希望在那里找到一个巨大的碎片,但是当我按照规定执行碎片计算时

free_space / (data_length + index_length)

事实证明,我的碎片只有0.2%。恕我直言,这是非常不现实的。

因此,主要问题是:

  1. 如何检查MySQL中特定索引的碎片,而不是整个表格
  2. OPTIMIZE TABLE是否像SQL Server一样实际修复了索引的内部/外部碎片?
  3. 当我在MySQL中优化表时,它实际上会重建表上的所有索引吗?
  4. 认为减少索引的物理空间(而不重建树本身)实际上转化为更好的性能是否现实?

优化表肯定会清除innodb上的聚集索引

1
这是一个很大的问题,而不是编程问题。将被移动到它所属的地方:>

Answers:


6

索引碎片被高估了。不用担心。

InnoDB将两个相邻的略为空的块合并为自然处理。

BTree上的随机动作会使其自然趋向于平均达到69%的满负荷。当然,这不是100%,但是“修复”的开销是不值得的。

SHOW TABLE STATUS 为您提供了一些指标,但它们存在缺陷-“ Data_free”包含某些“可用”空间,但不包含其他“可用”空间。

每个块中都有未使用的空间。免费的16KB块;免费的“范围”(nMB块);等待收割的MVCC行;非叶节点有自己的碎片;等等

Percona和Oracle使用不同的方式查看索引的大小(块数)。由于“免费”的定义有限,我发现它们都不有用。似乎块(每个16KB)是按块(几个MB)分配的,因此使人们相信存在各种碎片。实际上,它通常只是这些多MB块之一的大部分。而且OPTIMIZE TABLE不一定收回任何空间。

如果SQL Server使用的是BTree,那么这是在说“没有碎片”。想一想“块拆分”会发生什么。或考虑不断进行碎片整理的开销。无论哪种方式,您都会输。

还要注意,表和索引本质上是相同的结构:

  • B +树,基于某些索引
  • “数据”基于主键;每个二级索引都是基于其索引的B + Tree。
  • “数据”的叶节点包含表的所有列。
  • 次要索引的叶节点包含该次要索引的列以及PRIMARY KEY的列。

如果有的话innodb_file_per_table = ON,通过查看.ibd文件的大小,可以清楚地看到OPTIMIZE TABLE之后的收缩(如果有)。对于OFF,该信息被埋藏在中ibdata1,但SHOW TABLE STATUS由于所有“可用”空间都属于每个表,因此该信息可能相当准确。好吧,除了预先分配的块。

您可能会注意到,新优化的每张表文件具有完全为4M,5M,6M或7M的Data_free。同样,这是预先分配的信息,无法为您提供详细信息。

我在InnoDB工作了十多年;我处理过成千上万张不同大小的表。我说的是千分之一的桌子才真正需要OPTIMIZE TABLE。在其他表上使用它是浪费。

105列很多,但也许不太多。

一张桌子上有55个索引吗?那很不好。即每个更新55次INSERT。让我们进一步讨论。请记住,INDEX(a)如果您也这样做,那是没有用的INDEX(a,b)。而且INDEX(flag)由于基数低而没有用。(但INDEX(flag, foo)可能有用。)

问题1:没有好的方法来检查数据或辅助索引中所有形式的碎片。

Q2,Q3:OPTIMIZE TABLE通过CREATEing一个新表和INSERTing所有行,然后RENAMEing和来重建表DROPping。按PK顺序重新插入数据可确保对数据进行良好的碎片整理。索引是另一回事。

Q4:你可以 DROPreCREATE每个索引把它清理干净。但这是一个极其缓慢的过程。5.6可以加快速度,但是我不知道它们是否有助于碎片整理。

也有可能ALTER TABLE ... DISABLE KEYS,然后ENABLE他们。这样可以一次更高效地重建所有二级索引。


瑞克,我的意思是“ 105”字段,而不是文件
Nicolas

1

如何检查MySQL中特定索引的碎片,而不是整个表格

通过。

OPTIMIZE TABLE是否像SQL Server一样实际修复了索引的内部/外部碎片?

它将完全重建表及其索引。

当我在MySQL中优化表时,它实际上会重建表上的所有索引吗?

这是具有相同答案的相同问题。

认为减少索引的物理空间(而不重建树本身)实际上转化为更好的性能是否现实?

认为您可以减少空间而不重建树是不现实的。他们一起去。


回答#1:虽然它不是很准确,但是SHOW TABLE STATUS LIKE 'mytable'会在data free列中给出提示。dev.mysql.com/doc/refman/5.6/en/show-table-status.html
讨伐异教徒Keriaki

我知道,但是那仍然缺少特定索引的空间
Nicolas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.