文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  ANALYZE TABLE 语句

15.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]
    [{MANUAL | AUTO} UPDATE]

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 TABLE 带有 UPDATE HISTOGRAM 子句会为指定的表列生成直方图统计信息,并将其存储在数据字典中。此语法只允许一个表名。MySQL 还支持将单个列的直方图设置为用户定义的 JSON 值。

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

此语句需要表上的 SELECTINSERT 权限。

ANALYZE TABLEInnoDBNDBMyISAM 表一起使用。它不适用于视图。

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

ANALYZE TABLE 支持分区表,您可以使用 ALTER TABLE ... ANALYZE PARTITION 分析一个或多个分区;有关更多信息,请参见 第 15.1.9 节“ALTER TABLE 语句”第 26.3.4 节“分区维护”

在分析期间,表将被 InnoDBMyISAM 的读锁锁定。

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

ANALYZE TABLE 输出

ANALYZE TABLE 返回一个结果集,其中包含以下表格中显示的列。

表名
Op analyzehistogram
Msg_type statuserrorinfonotewarning
Msg_text 信息消息
密钥分布分析

不带 HISTOGRAM 子句的 ANALYZE TABLE 会执行密钥分布分析并将分布存储到表或表中。任何现有的直方图统计信息将保持不受影响。

如果表自上次密钥分布分析以来没有更改,则不会再次分析该表。

MySQL 使用存储的密钥分布来决定应按什么顺序连接表,以连接非常量的表。此外,在决定对特定查询使用哪个索引时,可以使用密钥分布。

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

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

您可以通过启用 innodb_stats_persistent 使 ANALYZE TABLE 收集的 统计信息 更精确、更稳定,如 第 17.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 中密钥分布分析的更多信息,请参见 第 17.8.10.1 节“配置持久优化器统计信息参数”第 17.8.10.3 节“估计 InnoDB 表的 ANALYZE TABLE 复杂性”

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

直方图统计分析

HISTOGRAM 子句的 ANALYZE TABLE 允许管理表列值的直方图统计信息。有关直方图统计信息的详细信息,请参见 第 10.9.6 节“优化器统计信息”

以下直方图操作可用

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

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

    可选的 AUTO UPDATE 子句启用表的直方图自动更新。启用后,对该表的 ANALYZE TABLE 语句会自动更新直方图,使用与上次由 WITH ... BUCKETS 指定的桶数相同,如果之前为此表设置了此选项。此外,当重新计算表的持久统计信息时(请参见 第 17.8.10.1 节“配置持久优化器统计信息参数”),InnoDB 后台统计线程也会更新直方图。 MANUAL UPDATE 禁用自动更新,是未指定时的默认设置。

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

存储的直方图管理语句只影响指定的列。请考虑以下语句

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;

第一个语句更新 c1c2c3 列的直方图,替换这些列的任何现有直方图。第二个语句更新 c1c3 列的直方图,而 c2 直方图不受影响。第三个语句删除 c2 的直方图,而 c1c3 的直方图不受影响。

在对用户数据进行采样以构建直方图时,并非所有值都已读取;这可能会导致丢失一些被认为很重要的值。在这种情况下,修改直方图或根据您自己的标准(例如,完整数据集)显式设置您自己的直方图可能会有用。 ANALYZE TABLE tbl_name UPDATE HISTOGRAM ON col_name USING DATA 'json_data' 使用与从 Information Schema COLUMN_STATISTICS 表显示 HISTOGRAM 列值时使用的相同 JSON 格式提供的数据来更新直方图表的列。使用 JSON 数据更新直方图时,只能修改一列。

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

mysql> ANALYZE TABLE t UPDATE HISTOGRAM ON c1;
+-------+-----------+----------+-----------------------------------------------+
| Table | Op        | Msg_type | Msg_text                                      |
+-------+-----------+----------+-----------------------------------------------+
| h.t   | histogram | status   | Histogram statistics created for column 'c1'. |
+-------+-----------+----------+-----------------------------------------------+
1 row in set (0.00 sec)

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

mysql> TABLE information_schema.column_statistics\G
*************************** 1. row ***************************
SCHEMA_NAME: h
 TABLE_NAME: t
COLUMN_NAME: c1
  HISTOGRAM: {"buckets": [], "data-type": "int", "auto-update": false,
"null-values": 0.0, "collation-id": 8, "last-updated": "2024-03-26
16:54:43.674995", "sampling-rate": 1.0, "histogram-type": "singleton",
"number-of-buckets-specified": 100}   
1 row in set (0.00 sec)

现在我们删除直方图,当我们检查 COLUMN_STATISTICS 时,它为空

mysql> ANALYZE TABLE t DROP HISTOGRAM ON c1;
+-------+-----------+----------+-----------------------------------------------+
| Table | Op        | Msg_type | Msg_text                                      |
+-------+-----------+----------+-----------------------------------------------+
| h.t   | histogram | status   | Histogram statistics removed for column 'c1'. |
+-------+-----------+----------+-----------------------------------------------+
1 row in set (0.01 sec)

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

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

mysql> ANALYZE TABLE t UPDATE HISTOGRAM ON c1 
    ->     USING DATA '{"buckets": [], "data-type": "int", "auto-update": false,
    ->               "null-values": 0.0, "collation-id": 8, "last-updated": "2024-03-26
    ->               16:54:43.674995", "sampling-rate": 1.0, "histogram-type": "singleton",
    ->               "number-of-buckets-specified": 100}';   
+-------+-----------+----------+-----------------------------------------------+
| Table | Op        | Msg_type | Msg_text                                      |
+-------+-----------+----------+-----------------------------------------------+
| h.t   | histogram | status   | Histogram statistics created for column 'c1'. |
+-------+-----------+----------+-----------------------------------------------+

mysql> TABLE information_schema.column_statistics\G
*************************** 1. row ***************************
SCHEMA_NAME: h
 TABLE_NAME: t
COLUMN_NAME: c1
  HISTOGRAM: {"buckets": [], "data-type": "int", "auto-update": false,
"null-values": 0.0, "collation-id": 8, "last-updated": "2024-03-26
16:54:43.674995", "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 值需要足够的权限来设置受限会话系统变量。请参见 第 7.1.9.1 节,“系统变量权限”

如果用于直方图生成的预计要读入内存的数据量超过 histogram_generation_max_mem_size 定义的限制,MySQL 将对数据进行采样,而不是将所有数据读入内存。采样在整个表中均匀分布。MySQL 使用 SYSTEM 采样,这是一种页面级采样方法。

Information Schema COLUMN_STATISTICS 表中 HISTOGRAM 列中的 sampling-rate 值可以查询以确定用于创建直方图的数据的比例。sampling-rate 是 0.0 到 1.0 之间的数字。值为 1 表示读取了所有数据(没有采样)。

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

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-rate 值为 0.0491431208869665 表示大约 4.9% 的 birth_date 列数据被读入内存以生成直方图统计信息。

InnoDB 存储引擎为存储在 InnoDB 表中的数据提供了自己的采样实现。MySQL 在存储引擎没有提供自己的采样实现时使用的默认采样实现需要完全表扫描,这对于大型表来说成本很高。InnoDB 采样实现通过避免完全表扫描来提高采样性能。

sampled_pages_readsampled_pages_skipped INNODB_METRICS 计数器可用于监视 InnoDB 数据页的采样。(有关一般 INNODB_METRICS 计数器使用信息的更多信息,请参见 第 28.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)

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

有关为直方图生成执行的内存分配的信息,请监视 Performance Schema memory/sql/histograms 仪器。请参见 第 29.12.20.10 节,“内存摘要表”

其他注意事项

ANALYZE TABLE 清除 Information Schema INNODB_TABLESTATS 表中的表统计信息,并将 STATS_INITIALIZED 列设置为 Uninitialized。统计信息会在下次访问表时再次收集。