Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  MySQL Performance Schema  /  Performance Schema Statement Digests and Sampling

29.10 性能模式语句摘要和采样

MySQL 服务器可以维护语句摘要信息。摘要过程将每个 SQL 语句转换为标准形式(语句摘要),并从标准结果计算 SHA-256 哈希值(摘要哈希值)。标准化允许类似语句被分组和总结,以暴露服务器执行的语句类型和频率信息。对于每个摘要,一个代表语句的样本被存储。该节描述了语句摘要和采样如何发生以及它们如何有用。

摘要发生在解析器中,不管性能模式是否可用,以便其他功能,如 MySQL Enterprise 防火墙和查询重写插件,可以访问语句摘要。

语句摘要通用概念

当解析器接收到 SQL 语句时,它计算语句摘要,如果该摘要是需要的,即以下任何条件为真:

  • 性能模式摘要仪表板启用

  • MySQL Enterprise 防火墙启用

  • 查询重写插件启用

解析器也用于 STATEMENT_DIGEST_TEXT()STATEMENT_DIGEST() 函数,这些函数可以由应用程序调用,以从 SQL 语句计算标准化语句摘要和摘要哈希值。

系统变量 max_digest_length 的值确定了每个会话中用于计算标准化语句摘要的最大字节数。一旦使用了该数量的空间,截断就会发生:不会收集或计算语句的其他标记。语句在截断点后不同被认为是相同的,如果比较或聚合摘要统计信息。

Warning

将系统变量 max_digest_length 设置为零将禁用摘要生产,也禁用了服务器功能,该功能需要摘要。

在计算标准化语句后,从中计算 SHA-256 哈希值。此外:

  • 如果 MySQL Enterprise 防火墙启用,它将被调用,并且计算的摘要将被提供给它。

  • 如果任何查询重写插件启用,它将被调用,并且语句摘要和摘要值将被提供给它。

  • 如果性能模式的摘要仪表板启用,它将复制标准化语句摘要,分配最多 performance_schema_max_digest_length 字节的空间。因此,如果 performance_schema_max_digest_length 小于 max_digest_length,复制的标准化语句摘要将相对于原始摘要被截断。复制的标准化语句摘要将被存储在适当的性能模式表中,连同从原始标准化语句计算的 SHA-256 哈希值。(如果性能模式截断了其复制的标准化语句摘要相对于原始摘要,它不会重新计算 SHA-256 哈希值。)

语句标准化将语句文本转换为更标准化的摘要字符串表示形式,该形式保留了语句结构的基本信息,同时删除了非essential 信息:

  • 对象标识符,如数据库和表名被保留。

  • 文字值被转换为参数标记。标准化语句不保留信息,如名称、密码、日期等。

  • 注释被删除,空白符被调整。

考虑以下语句:

SELECT * FROM orders WHERE customer_id=10 AND quantity>20
SELECT * FROM orders WHERE customer_id = 20 AND quantity > 100

为了标准化这些语句,解析器用 ? 替换数据值,并调整空白符。两个语句产生相同的标准化形式,因此被认为是 相同的

SELECT * FROM orders WHERE customer_id = ? AND quantity > ?

标准化语句包含较少的信息,但仍然代表原始语句。其他类似的语句具有不同的数据值,但具有相同的标准化形式。

现在考虑这些语句:

SELECT * FROM customers WHERE customer_id = 1000
SELECT * FROM orders WHERE customer_id = 1000

在这种情况下,标准化语句不同,因为对象标识符不同:

SELECT * FROM customers WHERE customer_id = ?
SELECT * FROM orders WHERE customer_id = ?

如果标准化产生的语句超过了摘要缓冲区中的可用空间(由 max_digest_length 确定),则会截断,并以 ... 结尾。长标准化语句仅在 ... 之后部分不同,被认为是相同的。考虑这些语句:

SELECT * FROM mytable WHERE cola = 10 AND colb = 20
SELECT * FROM mytable WHERE cola = 10 AND colc = 20

如果截断恰好发生在 AND 之后,两个语句都具有这种标准化形式:

SELECT * FROM mytable WHERE cola = ? AND ...

在这种情况下,第二列名称的差异被丢失,两个语句被认为是相同的。

性能模式中的语句摘要

在性能模式中,语句摘要涉及以下元素:

一些性能表具有存储原始 SQL 语句的列,从中计算摘要:

默认情况下,语句显示的最大可用空间为 1024 字节。要更改此值,请在服务器启动时设置 performance_schema_max_sql_text_length 系统变量。更改将影响所有列的存储要求。

系统变量 performance_schema_max_digest_length 确定了 Performance Schema 中每个语句的摘要值存储的最大字节数。然而,由于语句元素(如关键字和文字值)的内部编码,语句摘要的显示长度可能长于可用缓冲区大小。因此,从语句事件表的 DIGEST_TEXT 列中选择的值可能看起来超过 performance_schema_max_digest_length 值。

摘要表 events_statements_summary_by_digest 提供了服务器执行的语句的概况。它显示了应用程序执行的语句类型和频率。应用程序开发者可以使用该信息与表中的其他信息来评估应用程序的性能特征。例如,表中的等待时间、锁定时间或索引使用列可能会突出显示查询的低效率。这样,开发者可以了解应用程序中需要注意的部分。

摘要表 events_statements_summary_by_digest 的大小是固定的。默认情况下,Performance Schema 在启动时估算表大小。要明确指定表大小,请在服务器启动时设置 performance_schema_digests_size 系统变量。如果表满了,Performance Schema 将语句分组到特殊行中,具有 SCHEMA_NAMEDIGEST 值不匹配表中现有值的语句。这样,所有语句都可以被计数。然而,如果特殊行占据了执行的语句的很大百分比,可能需要通过增加 performance_schema_digests_size 来增加摘要表的大小。

语句摘要内存使用

对于生成非常长的语句的应用程序,仅在末尾不同,增加 max_digest_length 可以计算出能够区分语句的摘要。相反,减少 max_digest_length 将导致服务器分配较少的内存用于摘要存储,但增加了较长语句聚合到同一个摘要的可能性。管理员应该注意,较大的值将导致相应增加的内存需求,特别是在涉及大量同时会话的工作负载中(服务器为每个会话分配 max_digest_length 字节)。

如前所述,解析器计算的标准化语句摘要的最大长度为 max_digest_length 字节,而 Performance Schema 中存储的标准化语句摘要的最大长度为 performance_schema_max_digest_length 字节。以下是关于 max_digest_lengthperformance_schema_max_digest_length 相对值的内存使用考虑:

因为性能模式语句事件表可能存储许多摘要,设置performance_schema_max_digest_length小于max_digest_length使管理员能够平衡以下因素:

  • 服务器功能外的长规范化语句摘要的需求

  • 许多并发会话,每个会话分配摘要计算内存

  • 性能模式语句事件表存储许多语句摘要时的内存消耗限制

performance_schema_max_digest_length设置不是每个会话的,而是每个语句的,并且一个会话可以在events_statements_history表中存储多个语句。典型的语句数目在这个表中是每个会话10个,因此每个会话消耗了performance_schema_max_digest_length值10倍的内存,仅仅是这个表。

此外,还有许多全局收集的语句(和摘要),特别是在events_statements_history_long表中。在这里,N个语句存储消耗了Nperformance_schema_max_digest_length值的内存。

要评估SQL语句存储和摘要计算的内存使用情况,请使用SHOW ENGINE PERFORMANCE_SCHEMA STATUS语句,或者监控这些仪表:

mysql> SELECT NAME
       FROM performance_schema.setup_instruments
       WHERE NAME LIKE '%.sqltext';
+------------------------------------------------------------------+
| NAME                                                             |
+------------------------------------------------------------------+
| memory/performance_schema/events_statements_history.sqltext      |
| memory/performance_schema/events_statements_current.sqltext      |
| memory/performance_schema/events_statements_history_long.sqltext |
+------------------------------------------------------------------+

mysql> SELECT NAME
       FROM performance_schema.setup_instruments
       WHERE NAME LIKE 'memory/performance_schema/%.tokens';
+----------------------------------------------------------------------+
| NAME                                                                 |
+----------------------------------------------------------------------+
| memory/performance_schema/events_statements_history.tokens           |
| memory/performance_schema/events_statements_current.tokens           |
| memory/performance_schema/events_statements_summary_by_digest.tokens |
| memory/performance_schema/events_statements_history_long.tokens      |
+----------------------------------------------------------------------+

语句采样

性能模式使用语句采样来收集代表每个摘要值的语句在events_statements_summary_by_digest表中的信息。这些列存储采样语句信息:QUERY_SAMPLE_TEXT(语句文本),QUERY_SAMPLE_SEEN(语句被看到的时间),和QUERY_SAMPLE_TIMER_WAIT(语句等待或执行时间)。性能模式每次选择采样语句时都会更新这三个列。

当插入新表行时,产生行摘要值的语句将被存储为当前示例语句,关联到摘要中。从那时起,当服务器看到具有相同摘要值的其他语句时,它将确定是否使用新语句来替换当前示例语句(即是否重新采样)。重新采样策略基于当前示例语句和新语句的比较等待时间,以及可选地,当前示例语句的年龄:

  • 基于等待时间的重新采样:如果新语句的等待时间大于当前示例语句的等待时间,则新语句将成为当前示例语句。

  • 基于年龄的重新采样:如果 performance_schema_max_digest_sample_age 系统变量的值大于零,并且当前示例语句的年龄超过了该值那么多秒,则当前语句被认为是 太旧,并且新语句将取代它。这甚至发生在新语句的等待时间小于当前示例语句的等待时间的情况下。

默认情况下, performance_schema_max_digest_sample_age 为 60 秒(1 分钟)。要更改示例语句 过期 的速度,可以增加或减少该值。要禁用基于年龄的重新采样策略,请将 performance_schema_max_digest_sample_age 设置为 0。