存储引擎收集表统计信息以供优化器使用。表统计信息基于值组,其中一个值组是具有相同键前缀值的一组行。对于优化器目的,一个重要的统计信息是平均值组大小。
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
值不同:
不是 true 当 expr1
= expr2
expr1
或 expr2
(或两者)是 NULL
的时候。这影响了 ref
访问对于形式为
的比较:MySQL 不会访问表如果当前值 tbl_name.key
= expr
expr
是 NULL
,因为比较不能为 true。
对于 =
比较,不管表中有多少 NULL
值,对优化器目的来说,相关的值是非 NULL
值组的平均大小。然而,MySQL 目前不允许收集或使用该平均大小。
对于 InnoDB
和 MyISAM
表,您可以通过 innodb_stats_method
和 myisam_stats_method
系统变量控制表统计信息的收集。这些变量有三个可能的值,区别如下:
-
当变量设置为
nulls_equal
时,所有NULL
值被视为相同(即它们都形成一个值组)。如果
NULL
值组大小远远高于平均非NULL
值组大小,这种方法会使平均值组大小上升。这使索引对优化器目的变得不那么有用,导致优化器不使用索引进行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
方法。