Skip to content

Commit

Permalink
reference: update statement summary tables (#3145)
Browse files Browse the repository at this point in the history
  • Loading branch information
djshow832 authored May 25, 2020
1 parent 13a6876 commit 4289e87
Showing 1 changed file with 120 additions and 116 deletions.
236 changes: 120 additions & 116 deletions statement-summary-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ aliases: ['/docs-cn/dev/reference/performance/statement-summary/']

针对 SQL 性能相关的问题,MySQL 在 `performance_schema` 提供了 [statement summary tables](https://dev.mysql.com/doc/refman/5.6/en/statement-summary-tables.html),用来监控和统计 SQL。例如其中的一张表 `events_statements_summary_by_digest`,提供了丰富的字段,包括延迟、执行次数、扫描行数、全表扫描次数等,有助于用户定位 SQL 问题。

为此,从 3.0.4 版本开始,TiDB 也提供系统表 `events_statements_summary_by_digest`,从 3.0.8 开始提供系统表 `events_statements_summary_by_digest_history`。本文将详细介绍这两张表,以及如何利用它们来排查 SQL 性能问题。
为此,从 4.0.0-rc.1 版本开始,TiDB `information_schema` 中提供与 `events_statements_summary_by_digest` 功能相似的系统表:

## `events_statements_summary_by_digest`
- `statements_summary`
- `statements_summary_history`
- `cluster_statements_summary`
- `cluster_statements_summary_history`

`events_statements_summary_by_digest``performance_schema` 里的一张系统表,它把 SQL 按 SQL digest 和 plan digest 分组,统计每一组的 SQL 信息。
本文将详细介绍这些表,以及如何利用它们来排查 SQL 性能问题。

## `statements_summary`

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

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

Expand All @@ -31,18 +38,16 @@ select * from employee where id in (...) and salary between ? and ?;

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

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

为了监控指标的即时性,`events_statements_summary_by_digest` 里的数据定期被清空,只展现最近一段时间内的聚合结果。清空周期由系统变量 `tidb_stmt_summary_refresh_interval` 设置。如果刚好在清空之后进行查询,显示的数据可能很少。
`statements_summary` 用于保存 SQL 监控指标聚合后的结果。一般来说,每一项监控指标都包含平均值和最大值。例如执行延时对应 `AVG_LATENCY``MAX_LATENCY` 两个字段,分别是平均延时和最大延时。

因为 TiDB 中的很多概念不同于 MySQL,所以 TiDB 中 `events_statements_summary_by_digest` 的表结构与 MySQL 中的有很大区别
为了监控指标的即时性,`statements_summary` 里的数据定期被清空,只展现最近一段时间内的聚合结果。清空周期由系统变量 `tidb_stmt_summary_refresh_interval` 设置。如果刚好在清空之后进行查询,显示的数据可能很少

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

```
SUMMARY_BEGIN_TIME: 2020-01-02 11:00:00
SUMMARY_END_TIME: 2020-01-02 11:30:00
STMT_TYPE: select
STMT_TYPE: Select
SCHEMA_NAME: test
DIGEST: 0611cc2fe792f8c146cc97d39b31d9562014cf15f8d41f23a4938ca341f54182
DIGEST_TEXT: select * from employee where id = ?
Expand Down Expand Up @@ -74,7 +79,109 @@ select * from employee where id in (...) and salary between ? and ?;
>
> 在 TiDB 中,statement summary tables 中字段的时间单位是纳秒 (ns),而 MySQL 中的时间单位是皮秒 (ps)。
### 表的字段介绍
## `statements_summary_history`

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

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

## `cluster_statements_summary``cluster_statements_summary_history`

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

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

## 参数配置

以下系统变量用于控制 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 的历史的数量,默认值是 `24`
- `tidb_stmt_summary_max_stmt_count`:statement summary tables 保存的 SQL 种类数量,默认 200 条。当 SQL 种类超过该值时,会移除最近没有使用的 SQL。
- `tidb_stmt_summary_max_sql_length`:字段 `DIGEST_TEXT``QUERY_SAMPLE_TEXT` 的最大显示长度,默认值是 4096。
- `tidb_stmt_summary_internal_query`:是否统计 TiDB 的内部 SQL。1 代表统计,0 代表不统计,默认不统计。

statement summary 配置示例如下:

```sql
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 分钟清空一次。因为 24 * 30 分钟 = 12 小时,所以 `statements_summary_history` 保存最近 12 小时的历史数据。

以上几个系统变量都有 global 和 session 两种作用域,它们的生效方式与其他系统变量不一样:

- 设置 global 变量后整个集群立即生效
- 设置 session 变量后当前 TiDB server 立即生效,这对于调试单个 TiDB server 比较有用
- 优先读 session 变量,没有设置过 session 变量才会读 global 变量
- 把 session 变量设为空字符串,将会重新读 global 变量

> **注意:**
>
> `tidb_stmt_summary_history_size``tidb_stmt_summary_max_stmt_count``tidb_stmt_summary_max_sql_length` 这些配置都影响内存占用,建议根据实际情况调整,不宜设置得过大。
## 目前的限制

Statement summary tables 现在还存在以下限制:

- TiDB server 重启后 statement summary 会丢失。因为 statement summary tables 是内存表,不会持久化数据,所以一旦 server 被重启,statement summary 随之丢失。

## 排查示例

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

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

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

```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:

```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 |
+-------------+-------------+------------+-----------------------------------------------------------------------+
| 7855660 | 1122237 | 7 | select avg(salary) from employee where company_id=2013 |
| 7241960 | 1448392 | 5 | select * from employee join company on employee.company_id=company.id |
| 2084081 | 1042040 | 2 | select * from employee where name='eric' |
+-------------+-------------+------------+-----------------------------------------------------------------------+
3 rows in set (0.00 sec)
```

## 表的字段介绍

下面介绍 `statements_summary` 表中各个字段的含义。

SQL 的基础信息:

Expand All @@ -99,6 +206,8 @@ SQL 的基础信息:
在 TiDB server 上的执行数据:

- `EXEC_COUNT`:这类 SQL 的总执行次数
- `SUM_ERRORS`:执行过程中遇到的 error 的总数
- `SUM_WARNINGS`:执行过程中遇到的 warning 的总数
- `SUM_LATENCY`:这类 SQL 的总延时
- `MAX_LATENCY`:这类 SQL 的最大延时
- `MIN_LATENCY`:这类 SQL 的最小延时
Expand All @@ -112,11 +221,9 @@ SQL 的基础信息:

和 TiKV Coprocessor Task 相关的字段:

- `COP_TASK_NUM`:每条 SQL 发送的 Coprocessor 请求数量
- `AVG_COP_PROCESS_TIME`:cop-task 的平均处理时间
- `SUM_COP_TASK_NUM`:发送 Coprocessor 请求的总数
- `MAX_COP_PROCESS_TIME`:cop-task 的最大处理时间
- `MAX_COP_PROCESS_ADDRESS`:执行时间最长的 cop-task 所在地址
- `AVG_COP_WAIT_TIME`:cop-task 的平均等待时间
- `MAX_COP_WAIT_TIME`:cop-task 的最大等待时间
- `MAX_COP_WAIT_ADDRESS`:等待时间最长的 cop-task 所在地址
- `AVG_PROCESS_TIME`:SQL 在 TiKV 的平均处理时间
Expand Down Expand Up @@ -156,106 +263,3 @@ SQL 的基础信息:
- `BACKOFF_TYPES`:遇到需要重试的错误时的所有错误类型及每种类型重试的次数,格式为 `类型:次数`。如有多种错误则用 `,` 分隔,例如 `txnLock:2,pdRPC:1`
- `AVG_AFFECTED_ROWS`:平均影响行数
- `PREV_SAMPLE_TEXT`:当 SQL 是 `COMMIT` 时,该字段为 `COMMIT` 的前一条语句;否则该字段为空字符串。当 SQL 是 `COMMIT` 时,按 digest 和 `prev_sample_text` 一起分组,即不同 `prev_sample_text``COMMIT` 也会分到不同的行

## `events_statements_summary_by_digest_history`

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

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

## 排查示例

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

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

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

```sql
SELECT avg_latency, exec_count, query_sample_text
FROM performance_schema.events_statements_summary_by_digest
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:

```sql
SELECT sum_latency, avg_latency, exec_count, query_sample_text
FROM performance_schema.events_statements_summary_by_digest_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 |
+-------------+-------------+------------+-----------------------------------------------------------------------+
| 7855660 | 1122237 | 7 | select avg(salary) from employee where company_id=2013 |
| 7241960 | 1448392 | 5 | select * from employee join company on employee.company_id=company.id |
| 2084081 | 1042040 | 2 | select * from employee where name='eric' |
+-------------+-------------+------------+-----------------------------------------------------------------------+
3 rows in set (0.00 sec)
```

## 参数配置

statement summary 功能默认关闭,通过设置系统变量打开,例如:

```sql
set global tidb_enable_stmt_summary = true;
```

statement summary 关闭后,系统表里的数据会被清空,下次打开后重新统计。经测试,打开后对性能几乎没有影响。

还有两个控制 statement summary 的系统变量:

- `tidb_stmt_summary_refresh_interval``events_statements_summary_by_digest` 的清空周期,单位是秒 (s),默认值是 `1800`
- `tidb_stmt_summary_history_size``events_statements_summary_by_digest_history` 保存每种 SQL 的历史的数量,默认值是 `24`

statement summary 配置示例如下:

```sql
set global tidb_stmt_summary_refresh_interval = 1800;
set global tidb_stmt_summary_history_size = 24;
```

以上配置生效后,`events_statements_summary_by_digest` 每 30 分钟清空一次,`events_statements_summary_by_digest_history` 保存最近 12 小时的历史数据。

以上两个系统变量都有 global 和 session 两种作用域,它们的生效方式与其他系统变量不一样:

- 设置 global 变量后整个集群立即生效
- 设置 session 变量后当前 TiDB server 立即生效,这对于调试单个 TiDB server 比较有用
- 优先读 session 变量,没有设置过 session 变量才会读 global 变量
- 把 session 变量设为空字符串,将会重新读 global 变量

由于 statement summary tables 是内存表,为了防止内存问题,需要限制保存的 SQL 条数和 SQL 的最大显示长度。这两个参数都在 config.toml 的 `[stmt-summary]` 类别下配置:

- 通过 `max-stmt-count` 更改保存的 SQL 种类数量,默认 200 条。当 SQL 种类超过 `max-stmt-count` 时,会移除最近没有使用的 SQL。
- 通过 `max-sql-length` 更改 `DIGEST_TEXT``QUERY_SAMPLE_TEXT` 的最大显示长度,默认是 4096。

> **注意:**
>
> `tidb_stmt_summary_history_size``max-stmt-count``max-sql-length` 这些配置都影响内存占用,建议根据实际情况调整,不宜设置得过大。
## 目前的限制

Statement summary tables 现在还存在一些限制:

- 查询 statement summary tables 时,只会显示当前 TiDB server 的 statement summary,而不是整个集群的 statement summary。
- TiDB server 重启后 statement summary 会丢失。因为 statement summary tables 是内存表,不会持久化数据,所以一旦 server 被重启,statement summary 随之丢失。

0 comments on commit 4289e87

Please sign in to comment.