Documentation Home
MySQL 8.0 参考手册  / 第8章优化  / 8.3 优化和索引  /  8.3.8 InnoDB和MyISAM索引统计收集

8.3.8 InnoDB和MyISAM索引统计收集

存储引擎收集有关表的统计信息以供优化器使用。表统计是基于值组的,其中值组是一组具有相同键前缀值的行。出于优化器的目的,一个重要的统计数据是平均值组大小。

MySQL 通过以下方式使用平均值组大小:

  • ref估计每次访问 必须读取多少行

  • 估计一个partial join产生了多少行,也就是一个操作产生的行数

    (...) JOIN tbl_name ON tbl_name.key = expr

随着索引的平均值组大小的增加,索引对于这两个目的的用处减少,因为每次查找的平均行数增加:为了使索引有利于优化目的,最好每个索引值都以较小的目标为目标表中的行数。当给定的索引值产生大量行时,索引的用处不大,MySQL 也不太可能使用它。

平均值组大小与表基数有关,表基数是值组的数量。该 SHOW INDEX语句显示基于 的基数值N/S,其中 N是表中的行数,S是平均值组大小。该比率在表中产生近似数量的值组。

对于基于<=>比较运算符的连接,NULL与任何其他值没有区别对待:NULL <=> NULL,就像任何其他 . N <=> NN

但是,对于基于=运算符的连接, NULL与非NULL值不同: 当 或 (或两者)为 时不为真。这会影响 对以下形式比较的访问: 如果当前值为 ,则MySQL 不会访问该表 ,因为比较不可能为真。 expr1 = expr2expr1expr2NULLreftbl_name.key = exprexprNULL

对于=比较,表中有多少NULL个值并不重要。出于优化目的,相关值是非NULL值组的平均大小。但是,MySQL 当前不支持收集或使用该平均大小。

对于InnoDB和表,您可以分别通过和 系统变量MyISAM 对表统计信息的收集进行一些控制 。这些变量具有三个可能的值,它们的区别如下: innodb_stats_methodmyisam_stats_method

  • 当变量设置为 时nulls_equal,所有NULL值都被视为相同(即,它们都形成一个值组)。

    如果NULL值组大小远高于平均非NULL值组大小,则此方法会使平均值组大小向上倾斜。这使得索引在优化器看来不如它对查找非NULL值的连接真正有用。因此,该 方法可能会导致优化器在应该访问时 nulls_equal不使用索引 。ref

  • 当变量设置为 时 nulls_unequalNULL 值不被视为相同。相反,每个 NULL值形成一个单独的大小为 1 的值组。

    如果您有很多NULL值,此方法会向下倾斜平均值组大小。如果非值组的平均NULL大小很大,将NULL每个值计为大小为 1 的组会导致优化器高估查找非值的连接的索引NULL 值。因此,当其他方法可能更好时 ,该nulls_unequal 方法可能会导致优化器使用此索引进行 查找。ref

  • 当变量设置为 时 nulls_ignoredNULL 值将被忽略。

如果您倾向于使用许多使用 <=>rather than的联接=NULL则值在比较中并不特殊,并且一个NULL等于另一个。在这种情况下,nulls_equal是合适的统计方法。

系统innodb_stats_method变量具有全局值;系统 myisam_stats_method变量具有全局值和会话值。设置全局值会影响来自相应存储引擎的表的统计信息收集。设置会话值仅影响当前客户端连接的统计信息收集。这意味着您可以强制使用给定的方法重新生成表的统计信息,而不会通过将会话值设置为 myisam_stats_method.

要重新生成MyISAM表统计信息,您可以使用以下任何一种方法:

关于使用 innodb_stats_methodand 的一些注意事项myisam_stats_method

  • 您可以强制显式收集表统计信息,如前所述。但是,MySQL 也可以自动收集统计信息。例如,如果在对表执行语句的过程中,其中一些语句修改了表,MySQL 可能会收集统计信息。(例如,这可能发生在批量插入或删除或某些 ALTER TABLE语句中。)如果发生这种情况,将使用任何值 innodb_stats_methodmyisam_stats_method当时有。因此,如果您使用一种方法收集统计信息,但是当稍后自动收集表的统计信息时系统变量设置为另一种方法,则使用另一种方法。

  • 无法判断使用哪种方法为给定表生成统计信息。

  • 这些变量仅适用于InnoDBMyISAM表。其他存储引擎只有一种收集表统计信息的方法。通常它更接近nulls_equal方法。