> For the complete documentation index, see [llms.txt](https://bohans.gitbook.io/ji-chu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bohans.gitbook.io/ji-chu/mysql/sql-you-hua/performance-schema/shi-yong/jian-cha-sql-yu-ju.md).

# 检查SQL语句

## **1. 启用插桩**

<mark style="color:orange;">**要启用语句检测，需要启用statement类型的插桩（默认已经启用）**</mark>

```sql
UPDATE setup_instruments
SET enabled = 'YES'
WHERE name LIKE 'statement/%'
  AND enabled = 'NO';
```

相关的插桩如下表：

<table data-view="cards"><thead><tr><th>插桩类</th><th>描述</th></tr></thead><tbody><tr><td><mark style="color:blue;"><strong>statement/sql</strong></mark></td><td>SQL语句，如 SELECT、CREATE TABLE等</td></tr><tr><td><mark style="color:blue;"><strong>statement/sp</strong></mark></td><td>存储过程控制</td></tr><tr><td><mark style="color:blue;"><strong>statement/scheduler</strong></mark></td><td>事件调度器</td></tr><tr><td><mark style="color:blue;"><strong>statement/com</strong></mark></td><td>命令，如 quit、kill、DROP DATABASE、Binlog Dump等<br>有些命令是用户不可用的，只能由 mysqld 进程调用</td></tr><tr><td><mark style="color:blue;"><strong>statement/abstract</strong></mark></td><td>包括 4 类命令：clone、Query、new_packet 和 relay_log</td></tr></tbody></table>

## 2. 启用消费者表

Performance Schema将语句指标存储在 <mark style="color:blue;">**events\_statements\_current**</mark>、<mark style="color:blue;">**events\_statements\_history**</mark> 和 <mark style="color:blue;">**events\_statements\_history\_long**</mark> 表中。因此，接着需要启用（enable）这三张消费者表：

```sql
UPDATE setup_consumers
SET enabled = 'YES'
WHERE name LIKE 'events_statements_%'
  AND enabled = 'NO';
```

{% hint style="info" %}
在5.7版本中， <mark style="color:blue;">**events\_statements\_current**</mark>、<mark style="color:blue;">**events\_statements\_history**</mark> 默认处于enabled状态，<mark style="color:blue;">**events\_statements\_history\_long**</mark> 则处于disabled状态。
{% endhint %}

## 3. 查询消费者表，找出需要优化的SQL语句

在 <mark style="color:blue;">**events\_statements\_history**</mark> 表中可以作为优化指标的列如下：

| 列                                                               | 描述                                                                                       | 重要性                                      |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------- |
| <mark style="color:blue;">**CREATED\_TMP\_DISK\_TABLES**</mark> | 查询创建的临时磁盘表的数量。                                                                           | <mark style="color:red;">**高**</mark>    |
| <mark style="color:blue;">**CREATED\_TMP\_TABLES**</mark>       | <p>查询创建的临时表的数量。<br></p>                                                                  | <mark style="color:orange;">**中**</mark> |
| <mark style="color:blue;">**SELECT\_FULL\_JOIN**</mark>         | 因为没有合适的索引，所以导致JOIN执行了全表扫描。                                                               | <mark style="color:red;">**高**</mark>    |
| <mark style="color:blue;">**SELECT\_FULL\_RANGE\_JOIN**</mark>  | JOIN操作是否使用了被引用表的范围搜索。                                                                    | <mark style="color:orange;">**中**</mark> |
| <mark style="color:blue;">**SELECT\_RANGE**</mark>              | JOIN操作是否使用了范围搜索来解析第一个表中的行。                                                               | 低                                        |
| <mark style="color:blue;">**SELECT\_RANGE\_CHECK**</mark>       | <p>如果JOIN操作没有索引，则会检查每一行之后的键。<br><strong>这是一种非常糟糕的症状，如果该值大于零，则需要重新考虑表中的索引设计。</strong></p> | <mark style="color:red;">**高**</mark>    |
| <mark style="color:blue;">**SELECT\_SCAN**</mark>               | <p>JOIN操作是否对第一个表执行了全表扫描。<br><strong>如果第一个表很大则会使一个问题。</strong></p>                        | <mark style="color:orange;">**中**</mark> |
| <mark style="color:blue;">**SORT\_MERGE\_PASSES**</mark>        | <p>排序必须执行的合并过程数。<br><strong>如果该值大于零且查询性能较低，则可能需要增加 sort\_buffer\_size 的值。</strong></p>   | 低                                        |
| <mark style="color:blue;">**SORT\_RANGE**</mark>                | 是否使用的是范围排序。                                                                              | 低                                        |
| <mark style="color:blue;">**SORT\_ROWS**</mark>                 | <p>排序的行数。<br><strong>如果排序的行数比返回的行数多，则可能需要优化查询。</strong></p>                              | <mark style="color:orange;">**中**</mark> |
| <mark style="color:blue;">**SORT\_SCAN**</mark>                 | <p>排序是否是通过扫描表完成的。<br><strong>这是一个非常糟糕的迹象，除非有意选择表中的所有行而不使用索引。</strong></p>                | <mark style="color:red;">**高**</mark>    |
| <mark style="color:blue;">**NO\_INDEX\_USED**</mark>            | 查询没有使用索引。                                                                                | <mark style="color:red;">**高**</mark>    |
| <mark style="color:blue;">**NO\_GOOD\_INDEX\_USED**</mark>      | <p>查询所用的索引不是最合适的。<br><strong>如果该值大于零，则需要重新考虑索引的设计。</strong></p>                          | <mark style="color:red;">**高**</mark>    |

要找出哪些语句需要优化，可以选择上述列中的任何一列，并将其与 0 进行比较。

### 找到所有没有使用合适索引的查询

```sql
SELECT
    thread_id,
    sql_text,
    rows_sent,
    rows_examined,
    created_tmp_disk_tables,
    created_tmp_tables,
    no_index_used,
    no_good_index_used
FROM events_statements_history
WHERE no_index_used > 0
   OR no_good_index_used > 0;
```

### 找出所有创建了临时表的查询

```sql
SELECT
    thread_id,
    sql_text,
    rows_sent,
    rows_examined,
    created_tmp_disk_tables,
    created_tmp_tables,
    no_index_used,
    no_good_index_used
FROM events_statements_history
WHERE created_tmp_disk_tables > 0
   OR created_tmp_tables > 0;
```

### 找出所有返回错误的查询

```sql
SELECT
    thread_id,
    sql_text,
    mysql_errno,
    returned_sqlstate,
    message_text,
    errors
FROM events_statements_history
WHERE errors > 0;
```

### 找出所有执行时间超过 5 秒的查询

```sql
SELECT
    *
FROM events_statements_history
WHERE timer_wait > 5000000000;
```

## 4. 使用sys Schema

sys schema提供了可用于查找有问题语句的视图，如下表所示：

<table><thead><tr><th width="329">视图</th><th>描述</th></tr></thead><tbody><tr><td><mark style="color:blue;"><strong>statement_analysis</strong></mark></td><td><p>具有聚合统计信息的规范化语句视图，按每个规范化语句的总执行时间进行排序。</p><p>类似于 events_statements_summary_by_digest表，但没有那么详细。</p></td></tr><tr><td><mark style="color:blue;"><strong>statements_with_errors_or_warnings</strong></mark> </td><td>所有引起错误或警告的规范化语句。</td></tr><tr><td><mark style="color:blue;"><strong>statements_with_full_table_scans</strong></mark> </td><td>所有执行了全表扫描的规范化语句。</td></tr><tr><td><mark style="color:blue;"><strong>statements_with_runtimes_in_95th_percentile</strong></mark></td><td>所有平均执行时间在前 95% 的规范化语句。</td></tr><tr><td><mark style="color:blue;"><strong>statements_with_sorting</strong></mark></td><td>所有执行了排序的规范化语句。</td></tr><tr><td><mark style="color:blue;"><strong>statements_with_temp_tables</strong></mark></td><td>所有使用了临时表的规范化语句。</td></tr></tbody></table>

sys schema 使用<mark style="color:blue;">**摘要文本**</mark>而不是查询文本，因此你将获得查询文本的摘要，而不是像直接访问Performance Schema那样获得的要么是SQL语句要么是摘要文本：

```sql
SELECT
    query
FROM sys.statements_with_temp_tables
WHERE db = 'sakila'
  AND query LIKE '% ORDER BY %';
  
+-----------------------------------------------------------------+
|query                                                            |
+-----------------------------------------------------------------+
|EXPLAIN SELECT `payment_date`  ...  BY `payment_date` ORDER BY ? |
+-----------------------------------------------------------------+
```
