存储引擎收集有关表的统计信息,供优化器使用。表统计信息基于值组,其中值组是具有相同键前缀值的行的集合。对于优化器而言,一个重要的统计信息是平均值组大小。
MySQL 在以下方面使用平均值组大小
估计每次
ref
访问需要读取多少行估计部分连接产生多少行,即由以下形式的操作产生的行数:
(...) JOIN tbl_name ON tbl_name.key = expr
随着索引的平均值组大小增加,索引对于这两个目的的用处就越小,因为每次查找的平均行数也会增加:为了使索引对优化目的有效,最好每个索引值都针对表中的少量行。当给定索引值产生大量行时,索引的用处就越小,MySQL 就不太可能使用它。
平均值组大小与表基数相关,表基数是值组的数量。 SHOW INDEX
语句会根据 N/S
显示基数值,其中 N
是表中的行数,S
是平均值组大小。该比率会产生表中值组的近似数量。
对于基于 <=>
比较运算符的连接,NULL
的处理方式与其他任何值相同:NULL <=> NULL
,就像任何其他 N
的
一样。N
<=> N
但是,对于基于 =
运算符的连接,NULL
不同于非 NULL
值:当 expr1
或 expr2
(或两者)为 NULL
时,
不为真。这会影响以下形式的比较的 expr1
= expr2
ref
访问:
:如果 tbl_name.key
= expr
expr
的当前值为 NULL
,MySQL 不会访问表,因为比较不可能为真。
对于 =
比较,表中存在多少个 NULL
值并不重要。对于优化目的,相关值为非 NULL
值组的平均大小。但是,MySQL 当前不支持收集或使用该平均大小。
对于 InnoDB
和 MyISAM
表,您可以通过 innodb_stats_method
和 myisam_stats_method
系统变量分别控制表统计信息的收集。这些变量具有三个可能的值,它们的不同之处在于以下方面
当变量设置为
nulls_equal
时,所有NULL
值都被视为相同(即,它们都形成一个值组)。如果
NULL
值组大小远大于平均非NULL
值组大小,则此方法会使平均值组大小向上倾斜。这使得索引在优化器看来,对于查找非NULL
值的连接来说,比实际的用处要小。因此,nulls_equal
方法可能会导致优化器在应该使用索引的情况下,不使用索引进行ref
访问。当变量设置为
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
方法。