10.3.8 InnoDB和MyISAM索引统计信息收集
存储引擎收集表的统计信息,以供优化器使用。表统计信息基于值组,值组是具有相同键前缀值的一组行。对于优化器目的来说,一个重要的统计信息是平均值组大小。
MySQL 使用平均值组大小在以下方式:
-
估算每个
ref访问所需读取的行数 -
估算部分连接产生的行数,即由操作
(...) JOIN tbl_name ON tbl_name.key = expr
当索引的平均值组大小增加时,该索引对于这两个目的来说变得不太有用,因为每个索引值目标的行数增加:为了使索引对优化器有用,它最好每个索引值都目标小于表中的行数。当给定的索引值产生了大量行时,该索引变得不太有用,MySQL也更不可能使用它。
平均值组大小与表卡drod性相关,这是指值组的数量。SHOW INDEX语句显示基于N/S的卡drod性值,其中N是表中的行数和S是平均值组大小。该比率yield一个approximate的值组数量在表中。
对于基于<=>比较运算符的连接,NULL 不会被特殊对待:NULL <=> NULL,与任何其他值N相同。
然而,对于基于=运算符的连接,NULL 与非NULL值不同: 不是真的,当expr1 = expr2expr1 或expr2(或两个都)为NULL时。这影响了ref访问对于形式的比较::MySQL 不会访问表,如果当前tbl_name.key = exprexpr的值为NULL,因为比较不能是真的。
对于=比较,不管表中有多少个NULL值。为了优化目的,相关值是非NULL值组的平均大小。但是,MySQL 目前还不支持收集或使用该平均大小。
对于 InnoDB 和 MyISAM 表,您可以通过设置 innodb_stats_method 和 myisam_stats_method 系统变量来控制表统计信息的收集。这些变量有三个可能的值,以下是它们的区别:
-
当变量设置为
nulls_equal时,将对所有NULL值进行处理(即它们都形成一个单一的值组)。如果
NULL值组的大小远高于非NULL值组的平均大小,这种方法会使得平均值组大小上升。这使得索引对优化器看起来不那么有用,特别是在执行 join 操作时寻找非NULL值。因此,nulls_equal方法可能会导致优化器在应该使用索引的情况下不使用索引。 -
当变量设置为
nulls_unequal时,不会将NULL值视为相同。相反,每个NULL值都会形成一个大小为 1 的值组。如果您有许多
NULL值,这种方法会使平均值组的大小下降。如果平均非NULL值组的大小很大,那么将每个NULL值计为1个组的大小,导致优化器对索引的估算过高,从而在查找非NULL值的连接中使用该索引。因此,nulls_unequal方法可能会导致优化器在其他方法下使用该索引进行ref查找。 -
当变量设置为
nulls_ignored时,NULL值将被忽略。
如果您通常使用许多连接该用<=>而不是=,那么在比较中NULL值不具特别性质,并且一个NULL值等于另一个。在这种情况下,nulls_equal是适当的统计方法。
系统变量innodb_stats_method具有全局值;系统变量myisam_stats_method具有全局和会话值。设置全局值将影响对应存储引擎的表统计信息。设置会话值将只影响当前客户端连接的统计信息。这意味着,您可以强制一个表的统计信息使用给定的方法,而不影响其他客户端,通过设置myisam_stats_method会话值。
要重新生成MyISAM表的统计信息,可以使用以下方法之一:
-
将表更改为使其统计信息失效(例如,插入一行,然后删除它),然后设置
myisam_stats_method并执行ANALYZE TABLE语句
使用innodb_stats_method和myisam_stats_method时需要注意以下几点:
-
您可以强制收集表统计信息,正如前面所描述的那样。然而,MySQL也可能自动收集统计信息。例如,在执行对某个表的语句时,如果这些语句修改了该表,MySQL可能会收集统计信息。(这可能发生在批量插入或删除操作中,或者一些
ALTER TABLE语句中,例如。)如果发生这种情况,统计信息将使用在该时刻的innodb_stats_method或myisam_stats_method变量中指定的方法。因此,如果您使用一种方法收集统计信息,但是在后续自动收集表统计信息时系统变量设置为另一方法,那么将使用另一方法。 -
没有办法知道用于生成给定表统计信息的方法是哪种。
-
这些变量仅适用于
InnoDB和MyISAM表。其他存储引擎只有一个方法来收集表统计信息。通常,这个方法更接近于nulls_equal方法。