添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
📣
TiDB Cloud Premium 开放公测中。为企业级工作负载提供无限扩展、即时弹性伸缩和高级安全保障。 立即体验 →

Statement Summary Tables




针对 SQL 性能相关的问题,MySQL 在 performance_schema 提供了 statement summary tables ,用来监控和统计 SQL。例如其中的一张表 events_statements_summary_by_digest ,提供了丰富的字段,包括延迟、执行次数、扫描行数、全表扫描次数等,有助于用户定位 SQL 问题。

为此,从 4.0.0-rc.1 版本开始,TiDB 在 information_schema 而不是 performance_schema )中提供与 events_statements_summary_by_digest 功能相似的系统表:

  • statements_summary
  • statements_summary_history
  • cluster_statements_summary
  • cluster_statements_summary_history

本文将详细介绍这些表,以及如何利用它们来排查 SQL 性能问题。

statements_summary

statements_summary information_schema 里的一张系统表,它把 SQL 按所属资源组、SQL digest 和 plan digest 分组,统计每一组的 SQL 信息。

此处的 SQL digest 与 slow log 里的 SQL digest 一样,是把 SQL 规一化后算出的唯一标识符。SQL 的规一化会忽略常量、空白符、大小写的差别。即语法一致的 SQL 语句,其 digest 也相同。

例如:

SELECT * FROM employee WHERE id IN (1, 2, 3) AND salary BETWEEN 1000 AND 2000; select * from EMPLOYEE where ID in (4, 5) and SALARY between 3000 and 4000;

归一化后都是:

select * from employee where id in (...) and salary between ? and ?;

此处的 plan digest 是把执行计划规一化后算出的唯一标识符。执行计划的规一化会忽略常量的差别。由于相同的 SQL 可能产生不同的执行计划,所以可能分到多个组,同一个组内的执行计划是相同的。

statements_summary 用于保存 SQL 监控指标聚合后的结果。一般来说,每一项监控指标都包含平均值和最大值。例如执行延时对应 AVG_LATENCY MAX_LATENCY 两个字段,分别是平均延时和最大延时。

为了监控指标的即时性, statements_summary 里的数据定期被清空,只展现最近一段时间内的聚合结果。清空周期由系统变量 tidb_stmt_summary_refresh_interval 设置。如果刚好在清空之后进行查询,显示的数据可能很少。

以下为查询 statements_summary 的部分结果:

SUMMARY_BEGIN_TIME: 2020-01-02 11:00:00 SUMMARY_END_TIME: 2020-01-02 11:30:00 STMT_TYPE: Select SCHEMA_NAME: test DIGEST: 0611cc2fe792f8c146cc97d39b31d9562014cf15f8d41f23a4938ca341f54182 DIGEST_TEXT: select * from employee where id = ? TABLE_NAMES: test.employee INDEX_NAMES: NULL SAMPLE_USER: root EXEC_COUNT: 3 SUM_LATENCY: 1035161 MAX_LATENCY: 399594 MIN_LATENCY: 301353 AVG_LATENCY: 345053 AVG_PARSE_LATENCY: 57000 MAX_PARSE_LATENCY: 57000 AVG_COMPILE_LATENCY: 175458 MAX_COMPILE_LATENCY: 175458 ........... AVG_MEM: 103 MAX_MEM: 103 AVG_DISK: 65535 MAX_DISK: 65535 AVG_AFFECTED_ROWS: 0 FIRST_SEEN: 2020-01-02 11:12:54 LAST_SEEN: 2020-01-02 11:25:24 QUERY_SAMPLE_TEXT: select * from employee where id=3100 PREV_SAMPLE_TEXT: PLAN_DIGEST: f415b8d52640b535b9b12a9c148a8630d2c6d59e419aad29397842e32e8e5de3 PLAN: Point_Get_1 root 1 table:employee, handle:3100

statements_summary_history

statements_summary_history 的表结构与 statements_summary 完全相同,用于保存历史时间段的数据。通过历史数据,可以排查过去出现的异常,也可以对比不同时间的监控指标。

字段 SUMMARY_BEGIN_TIME SUMMARY_END_TIME 代表历史时间段的开始时间和结束时间。

statements_summary_evicted

tidb_stmt_summary_max_stmt_count 系统变量用于限制 statements_summary statements_summary_history 这两张表在内存中可存储的 SQL digest 总数。当超出该限制时,TiDB 会从 statements_summary statements_summary_history 这两张表中驱逐最久未使用的 SQL digest。

statements_summary_evicted 表记录了发生 SQL digest 驱逐的时间段,以及该时间段内被驱逐的 SQL digest 数量。通过该表,你可以评估当前 tidb_stmt_summary_max_stmt_count 的配置是否适合你的工作负载。如果该表中存在记录,说明在某个时间点上 SQL digest 的数量曾超出过 tidb_stmt_summary_max_stmt_count 的限制。

TiDB Dashboard 的 SQL 语句分析列表页面 中,被驱逐的语句信息会显示在 Others 行中。

statement summary 的 cluster 表

statements_summary statements_summary_history statements_summary_evicted 仅显示单台 TiDB server 的 statement summary 数据。若要查询整个集群的数据,需要查询 cluster_statements_summary cluster_statements_summary_history cluster_statements_summary_evicted 表。

cluster_statements_summary 显示各台 TiDB server 的 statements_summary 数据, cluster_statements_summary_history 显示各台 TiDB server 的 statements_summary_history 数据,而 cluster_statements_summary_evicted 则显示各台 TiDB server 的 statements_summary_evicted 数据。这三张表用字段 INSTANCE 表示 TiDB server 的地址,其他字段与 statements_summary statements_summary_history statements_summary_evicted 表相同。

参数配置

以下系统变量用于控制 statement summary:

  • tidb_enable_stmt_summary :是否打开 statement summary 功能。1 代表打开,0 代表关闭,默认打开。statement summary 关闭后,系统表里的数据会被清空,下次打开后重新统计。经测试,打开后对性能几乎没有影响。

  • tidb_stmt_summary_refresh_interval statements_summary 的清空周期,单位是秒 (s),默认值是 1800

  • tidb_stmt_summary_history_size statements_summary_history 保存每种 SQL 的历史的数量,也是 statements_summary_evicted 的表容量,默认值是 24

  • tidb_stmt_summary_max_stmt_count :限制 statements_summary statements_summary_history 这两张表在内存中可存储的 SQL digest 总数。默认值为 3000 条。

    当超出该限制时,TiDB 会从 statements_summary statements_summary_history 这两张表中驱逐最久未使用的 SQL digest。这些被驱逐的 SQL digest 的数量将会被记录在 statements_summary_evicted 表中。

  • tidb_stmt_summary_max_sql_length :字段 DIGEST_TEXT QUERY_SAMPLE_TEXT 的最大显示长度,默认值是 4096。

  • tidb_stmt_summary_internal_query :是否统计 TiDB 的内部 SQL。1 代表统计,0 代表不统计,默认不统计。

statement summary 配置示例如下:

set global tidb_stmt_summary_max_stmt_count = 3000; set global tidb_enable_stmt_summary = true; set global tidb_stmt_summary_refresh_interval = 1800; set global tidb_stmt_summary_history_size = 24;

以上配置生效后, statements_summary 每 30 分钟清空一次, statements_summary_history 最多保存 3000 种 SQL 种类的数据,每种类型的 SQL 保存最近出现过的 24 个时间段的数据。 statements_summary_evicted 保存最近 24 个发生了 evict 的时间段记录; statements_summary_evicted 则以 30 分钟为一个记录周期,表容量为 24 个时间段。

为 statement summary 设定合适的大小

在系统运行一段时间后(视系统负载而定),可以查看 statements_summary 表检查是否发生了 evict,例如:

select @@global.tidb_stmt_summary_max_stmt_count; select count(*) from information_schema.statements_summary;
+-------------------------------------------+ | @@global.tidb_stmt_summary_max_stmt_count | +-------------------------------------------+ | 3000 | +-------------------------------------------+ 1 row in set (0.001 sec) +----------+ | count(*) | +----------+ | 3001 | +----------+ 1 row in set (0.001 sec)

可以发现 statements_summary 表已经满了。再查看 statements_summary_evicted 表检查 evict 的数据。

select * from information_schema.statements_summary_evicted;
+---------------------+---------------------+---------------+ | BEGIN_TIME | END_TIME | EVICTED_COUNT | +---------------------+---------------------+---------------+ | 2020-01-02 16:30:00 | 2020-01-02 17:00:00 | 59 | +---------------------+---------------------+---------------+ | 2020-01-02 16:00:00 | 2020-01-02 16:30:00 | 45 | +---------------------+---------------------+---------------+ 2 row in set (0.001 sec)

由上可知,对最多 59 种 SQL 发生了 evict。此时,建议将 statements_summary 表的容量至少增大 59 条记录,即至少增大至 3059 条。

目前的限制

由于 statement summary tables 默认都存储在内存中,TiDB server 重启后,statement summary 会全部丢失。

为解决该问题,TiDB v6.6.0 实验性地引入了 statement summary 持久化 功能,该功能默认为关闭。开启该功能后,历史数据不再存储在内存内,而是直接写入磁盘。TiDB server 重启后,历史数据也依然可用。

持久化 statements summary

目前的限制 一节所描述,默认情况下 statements summary 只在内存中维护,一旦 TiDB server 发生重启,所有 statements summary 数据都会丢失。自 v6.6.0 起,TiDB 实验性地提供了配置项 tidb_stmt_summary_enable_persistent 来允许用户控制是否开启 statements summary 持久化。

如果要开启 statements summary 持久化,可以在 TiDB 配置文件中添加如下配置:

[instance] tidb_stmt_summary_enable_persistent = true # 以下配置为默认值,可根据需求调整。 # tidb_stmt_summary_filename = "tidb-statements.log" # tidb_stmt_summary_file_max_days = 3 # tidb_stmt_summary_file_max_size = 64 # MiB # tidb_stmt_summary_file_max_backups = 0

开启 statements summary 持久化后,内存中只维护当前的实时数据,不再维护历史数据。历史数据生成后直接被写入磁盘文件,写入周期参考 参数配置 一节所描述的 tidb_stmt_summary_refresh_interval 。后续针对 statements_summary_history cluster_statements_summary_history 表的查询将结合内存和磁盘两处数据返回结果。

排查示例

下面用两个示例问题演示如何利用 statement summary 来排查。

SQL 延迟比较大,是不是服务端的问题?

例如客户端显示 employee 表的点查比较慢,那么可以按 SQL 文本来模糊查询:

SELECT avg_latency, exec_count, query_sample_text FROM information_schema.statements_summary WHERE digest_text LIKE 'select * from employee%';

结果如下, avg_latency 是 1 ms 和 0.3 ms,在正常范围,所以可以判定不是服务端的问题,继而排查客户端或网络问题。

+-------------+------------+------------------------------------------+ | avg_latency | exec_count | query_sample_text | +-------------+------------+------------------------------------------+ | 1042040 | 2 | select * from employee where name='eric' | | 345053 | 3 | select * from employee where id=3100 | +-------------+------------+------------------------------------------+ 2 rows in set (0.00 sec)

哪类 SQL 的总耗时最高?

假如上午 10:00 到 10:30 的 QPS 明显下降,可以从历史表中找出当时耗时最高的三类 SQL:

SELECT sum_latency, avg_latency, exec_count, query_sample_text FROM information_schema.statements_summary_history WHERE summary_begin_time='2020-01-02 10:00:00' ORDER BY sum_latency DESC LIMIT 3;

结果显示以下三类 SQL 的总延迟最高,所以这些 SQL 需要重点优化。

+-------------+-------------+------------+-----------------------------------------------------------------------+ | sum_latency | avg_latency | exec_count | query_sample_text | +-------------+-------------+------------+-----------------------------------------------------------------------+