Documentation Home

13.7.3.1 ANALYZE TABLE 语句

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name [, tbl_name] ...

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name
    UPDATE HISTOGRAM ON col_name [, col_name] ...
        [WITH N BUCKETS]

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL] 
    TABLE tbl_name
    UPDATE HISTOGRAM ON col_name [USING DATA 'json_data']

ANALYZE [NO_WRITE_TO_BINLOG | LOCAL]
    TABLE tbl_name
    DROP HISTOGRAM ON col_name [, col_name] ...

ANALYZE TABLE生成表统计信息:

  • ANALYZE TABLE没有任何一个 HISTOGRAM子句执行键分布分析并存储指定表的分布。对于MyISAM表, ANALYZE TABLE对于键分布分析等同于使用 myisamchk --analyze

  • ANALYZE TABLEwith UPDATE HISTOGRAM子句为指定的表列生成直方图统计信息并将它们存储在数据字典中。此语法只允许使用一个表名。MySQL 8.0.31 及之后的版本也支持将单列的直方图设置为用户自定义的 JSON 值。

  • ANALYZE TABLEwith DROP HISTOGRAM子句从数据字典中删除指定表列的直方图统计信息。此语法只允许使用一个表名。

此语句需要表SELECTINSERT权限。

ANALYZE TABLE适用于 InnoDBNDBMyISAM表格。它不适用于视图。

如果innodb_read_only启用了系统变量,ANALYZE TABLE可能会失败,因为它无法更新数据字典中使用 InnoDB. 对于ANALYZE TABLE更新键分布的操作,即使操作更新表本身(例如,如果它是一个MyISAM表)也可能会失败。要获取更新的分布统计信息,请设置 information_schema_stats_expiry=0.

ANALYZE TABLE支持分区表,可以ALTER TABLE ... ANALYZE PARTITION用来分析一个或多个分区;有关详细信息,请参阅第 13.1.9 节,“ALTER TABLE 语句”第 24.3.4 节,“分区维护”

在分析过程中,表被 和 的读锁 InnoDB锁定MyISAM

ANALYZE TABLE从表定义缓存中删除表,这需要刷新锁。如果有长时间运行的语句或事务仍在使用该表,则后续语句和事务必须等待这些操作完成才能释放刷新锁。因为ANALYZE TABLE它本身通常很快完成,所以涉及同一个表的延迟事务或语句可能并不明显是由于剩余的刷新锁。

默认情况下,服务器将ANALYZE TABLE语句写入二进制日志,以便它们复制到副本。要禁止记录日志,请指定可选 NO_WRITE_TO_BINLOG关键字或其别名 LOCAL

分析表输出

ANALYZE TABLE返回一个结果集,其列如下表所示。

柱子 价值
Table 表名
Op analyze或者histogram
Msg_type status, error, info,notewarning
Msg_text 信息性消息
密钥分布分析

ANALYZE TABLE没有任何一个 HISTOGRAM子句执行密钥分布分析并存储一个或多个表的分布。任何现有的直方图统计数据不受影响。

如果自上次键分布分析以来该表未发生变化,则不会再次分析该表。

MySQL 使用存储的键分布来决定表的连接顺序,以便连接常量以外的东西。此外,在决定将哪些索引用于查询中的特定表时,可以使用键分布。

要检查存储的密钥分布基数,请使用 SHOW INDEX语句或 INFORMATION_SCHEMA STATISTICS表。请参阅 第 13.7.7.22 节,“SHOW INDEX 语句”第 26.3.34 节,“INFORMATION_SCHEMA STATISTICS 表”

对于InnoDB表, ANALYZE TABLE通过对每个索引树执行随机潜水并相应地更新索引基数估计来确定索引基数。因为这些只是估计值,重复运行 ANALYZE TABLE可能会产生不同的数字。这使得表格ANALYZE TABLE速度很快InnoDB但不是 100% 准确,因为它没有考虑所有行。

您可以 通过启用使收集 的统计信息ANALYZE TABLE更精确、更稳定 innodb_stats_persistent,如第 15.8.10.1 节“配置持久优化器统计参数”中所述。启用后,在 对索引列数据进行重大更改后innodb_stats_persistent运行很重要ANALYZE TABLE,因为不会定期重新计算统计信息(例如在服务器重启后)。

如果innodb_stats_persistent启用,您可以通过修改 innodb_stats_persistent_sample_pages 系统变量来更改随机潜水次数。如果 innodb_stats_persistent禁用,请 innodb_stats_transient_sample_pages 改为修改。

有关键分布分析的更多信息 InnoDB,请参阅 第 15.8.10.1 节,“配置持久优化器统计参数”第 15.8.10.3 节,“估计 InnoDB 表的分析表复杂性”

MySQL 在连接优化中使用索引基数估计。如果连接未以正确的方式优化,请尝试运行 ANALYZE TABLE. 在少数情况下,ANALYZE TABLE您的特定表不能产生足够好的值,您可以使用FORCE INDEX查询来强制使用特定索引,或设置 max_seeks_for_key系统变量以确保 MySQL 更喜欢索引查找而不是表扫描。请参阅第 B.3.5 节,“与优化器相关的问题”

直方图统计分析

ANALYZE TABLEwith HISTOGRAM子句可以管理表列值的直方图统计信息。有关直方图统计的信息,请参阅 第 8.9.6 节,“优化器统计”

这些直方图操作可用:

  • ANALYZE TABLEwith UPDATE HISTOGRAM子句为指定的表列生成直方图统计信息并将它们存储在数据字典中。此语法只允许使用一个表名。

    可选子句指定直方图的桶数。取值 必须是1到1024之间的整数。如果省略该子句,则桶数为100。 WITH N BUCKETSN

  • ANALYZE TABLEwith DROP HISTOGRAM子句从数据字典中删除指定表列的直方图统计信息。此语法只允许使用一个表名。

存储直方图管理语句只影响命名列。考虑这些陈述:

ANALYZE TABLE t UPDATE HISTOGRAM ON c1, c2, c3 WITH 10 BUCKETS;
ANALYZE TABLE t UPDATE HISTOGRAM ON c1, c3 WITH 10 BUCKETS;
ANALYZE TABLE t DROP HISTOGRAM ON c2;

第一个语句更新列 c1c2和 的直方图c3,替换这些列的任何现有直方图。第二条语句更新 c1和的直方图c3,不 c2影响直方图。第三条语句删除 的直方图c2,留下c1和 的直方图c3不受影响。

在构建直方图的过程中对用户数据进行采样时,不会读取所有值;这可能会导致丢失一些被认为重要的值。在这种情况下,修改直方图或根据您自己的标准(例如完整数据集)明确设置您自己的直方图可能很有用。MySQL 8.0.31 添加了对更新直方图表列的支持,其中提供的数据与用于显示信息模式表中 的列值的 JSON 格式相同。使用 JSON 数据更新直方图时只能修改一列。 ANALYZE TABLE tbl_name UPDATE HISTOGRAM ON col_name USING DATA 'json_data'HISTOGRAMCOLUMN_STATISTICS

我们可以通过首先在 tableUSING DATA的列上生成直方图来说明 的用法,如下所示: c1t

mysql> ANALYZE TABLE t UPDATE HISTOGRAM ON c1;
+--------+-----------+----------+-----------------------------------------------+
| Table  | Op        | Msg_type | Msg_text                                      |
+--------+-----------+----------+-----------------------------------------------+
| mydb.t | histogram | status   | Histogram statistics created for column 'c1'. |
+--------+-----------+----------+-----------------------------------------------+

我们可以在 COLUMN_STATISTICS表中看到生成的直方图:

mysql> TABLE information_schema.column_statistics\G
*************************** 1. row ***************************
SCHEMA_NAME: mydb
 TABLE_NAME: t
COLUMN_NAME: c1
  HISTOGRAM: {"buckets": [[206, 0.0625], [456, 0.125], [608, 0.1875]],
"data-type": "int", "null-values": 0.0, "collation-id": 8, "last-updated":
"2022-10-11 16:13:14.563319", "sampling-rate": 1.0, "histogram-type":
"singleton", "number-of-buckets-specified": 100}

现在我们放下直方图,当我们检查时 COLUMN_STATISTICS,它现在是空的:

mysql> ANALYZE TABLE t DROP HISTOGRAM ON c1;
+--------+-----------+----------+-----------------------------------------------+
| Table  | Op        | Msg_type | Msg_text                                      |
+--------+-----------+----------+-----------------------------------------------+
| mydb.t | histogram | status   | Histogram statistics removed for column 'c1'. |
+--------+-----------+----------+-----------------------------------------------+

mysql> TABLE information_schema.column_statistics\G
Empty set (0.00 sec)

我们可以通过插入之前从表的 HISTOGRAM列中 获得的 JSON 表示来恢复删除的直方图COLUMN_STATISTICS,当我们再次查询该表时,我们可以看到直方图已经恢复到之前的状态:

mysql> ANALYZE TABLE t UPDATE HISTOGRAM ON c1 
    ->     USING DATA '{"buckets": [[206, 0.0625], [456, 0.125], [608, 0.1875]],
    ->               "data-type": "int", "null-values": 0.0, "collation-id":
    ->               8, "last-updated": "2022-10-11 16:13:14.563319",
    ->               "sampling-rate": 1.0, "histogram-type": "singleton",
    ->               "number-of-buckets-specified": 100}';   
+--------+-----------+----------+-----------------------------------------------+
| Table  | Op        | Msg_type | Msg_text                                      |
+--------+-----------+----------+-----------------------------------------------+
| mydb.t | histogram | status   | Histogram statistics created for column 'c1'. |
+--------+-----------+----------+-----------------------------------------------+

mysql> TABLE information_schema.column_statistics\G
*************************** 1. row ***************************
SCHEMA_NAME: mydb
 TABLE_NAME: t
COLUMN_NAME: c1
  HISTOGRAM: {"buckets": [[206, 0.0625], [456, 0.125], [608, 0.1875]],
"data-type": "int", "null-values": 0.0, "collation-id": 8, "last-updated":
"2022-10-11 16:13:14.563319", "sampling-rate": 1.0, "histogram-type":
"singleton", "number-of-buckets-specified": 100}

加密表(以避免在统计信息中暴露数据)或表不支持直方图生成 TEMPORARY

直方图生成适用于所有数据类型的列,除了几何类型(空间数据)和 JSON.

可以为存储的和虚拟生成的列生成直方图。

不能为单列唯一索引覆盖的列生成直方图。

直方图管理语句尝试执行尽可能多的请求操作,并报告剩余部分的诊断消息。例如,如果一条UPDATE HISTOGRAM语句命名了多个列,但其中一些列不存在或具有不受支持的数据类型,则会为其他列生成直方图,并为无效列生成消息。

直方图受这些 DDL 语句的影响:

  • DROP TABLE删除删除表中列的直方图。

  • DROP DATABASE删除已删除数据库中任何表的直方图,因为该语句删除了数据库中的所有表。

  • RENAME TABLE不删除直方图。相反,它会重命名重命名表的直方图以与新表名相关联。

  • ALTER TABLE删除或修改列的语句会删除该列的直方图。

  • ALTER TABLE ... CONVERT TO CHARACTER SET删除字符列的直方图,因为它们受字符集更改的影响。非字符列的直方图不受影响。

系统变量控制可用于直方图生成的 histogram_generation_max_mem_size 最大内存量。全局和会话值可以在运行时设置。

更改全局 histogram_generation_max_mem_size 值需要足够的权限来设置全局系统变量。更改会话 histogram_generation_max_mem_size 值需要足够的权限来设置受限会话系统变量。请参阅 第 5.1.9.1 节,“系统变量权限”

如果为生成直方图而读入内存的估计数据量超过了定义的限制 histogram_generation_max_mem_size,MySQL 将对数据进行采样,而不是将其全部读入内存。采样均匀分布在整个表上。MySQL使用SYSTEM采样,这是一种页面级别的采样方法。

可以查询表列中 的sampling-rate值 以确定为创建直方图而采样的数据分数。是介于 0.0 和 1.0 之间的数字。 值 1 表示已读取所有数据(无采样)。 HISTOGRAMINFORMATION_SCHEMA.COLUMN_STATISTICSsampling-rate

以下示例演示了采样。为了确保数据量超过 histogram_generation_max_mem_size 示例的限制,在为表的birth_date列 生成直方图统计信息之前,将限制设置为较低的值(2000000 字节) employees

mysql> SET histogram_generation_max_mem_size = 2000000;

mysql> USE employees;

mysql> ANALYZE TABLE employees UPDATE HISTOGRAM ON birth_date WITH 16 BUCKETS\G
*************************** 1. row ***************************
   Table: employees.employees
      Op: histogram
Msg_type: status
Msg_text: Histogram statistics created for column 'birth_date'.

mysql> SELECT HISTOGRAM->>'$."sampling-rate"'
       FROM INFORMATION_SCHEMA.COLUMN_STATISTICS
       WHERE TABLE_NAME = "employees"
       AND COLUMN_NAME = "birth_date";
+---------------------------------+
| HISTOGRAM->>'$."sampling-rate"' |
+---------------------------------+
| 0.0491431208869665              |
+---------------------------------+

sampling-rate0.0491431208869665 表示该 birth_date列中大约 4.9% 的数据被读入内存以生成直方图统计信息。

从 MySQL 8.0.19 开始,存储引擎为存储在表InnoDB中的数据提供了自己的采样实现。InnoDB当存储引擎不提供自己的存储引擎时,MySQL 使用的默认采样实现需要全表扫描,这对于大表来说代价高昂。InnoDB 采样实现通过避免全表扫描来提高采样性能 。

sampled_pages_readsampled_pages_skipped INNODB_METRICS计数器可用于监视InnoDB数据页 的采样。(有关一般 INNODB_METRICS计数器使用信息,请参阅 第 26.4.21 节,“INFORMATION_SCHEMA INNODB_METRICS 表”。)

以下示例演示了采样计数器的用法,这需要在生成直方图统计信息之前启用计数器。

mysql> SET GLOBAL innodb_monitor_enable = 'sampled%';

mysql> USE employees;

mysql> ANALYZE TABLE employees UPDATE HISTOGRAM ON birth_date WITH 16 BUCKETS\G
*************************** 1. row ***************************
   Table: employees.employees
      Op: histogram
Msg_type: status
Msg_text: Histogram statistics created for column 'birth_date'.

mysql> USE INFORMATION_SCHEMA;

mysql> SELECT NAME, COUNT FROM INNODB_METRICS WHERE NAME LIKE 'sampled%'\G
*************************** 1. row ***************************
 NAME: sampled_pages_read
COUNT: 43
*************************** 2. row ***************************
 NAME: sampled_pages_skipped
COUNT: 843

此公式基于采样计数器数据近似采样率:

sampling rate = sampled_page_read/(sampled_pages_read + sampled_pages_skipped)

基于采样计数器数据的采样率与表中列中 的sampling-rate值 大致相同 。 HISTOGRAMINFORMATION_SCHEMA.COLUMN_STATISTICS

有关为直方图生成执行的内存分配的信息,请监控 Performance Schema memory/sql/histograms工具。请参阅 第 27.12.20.10 节,“内存汇总表”

其他注意事项

ANALYZE TABLE从表中清除表统计信息 INFORMATION_SCHEMA.INNODB_TABLESTATS 并将STATS_INITIALIZED列设置为Uninitialized。下次访问表时会再次收集统计信息。