Skip to content

Commit

Permalink
Merge branch 'master' into expression_index_ga
Browse files Browse the repository at this point in the history
  • Loading branch information
wjhuang2016 authored Aug 13, 2021
2 parents f42d85a + 76a6118 commit 56a2449
Show file tree
Hide file tree
Showing 27 changed files with 624 additions and 329 deletions.
2 changes: 1 addition & 1 deletion best-practices/high-concurrency-best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ aliases: ['/docs-cn/dev/best-practices/high-concurrency-best-practices/','/docs-

如果要解决以上挑战,需要从 TiDB 数据切分以及调度的原理开始讲起。这里只作简单说明,详情可参阅[谈调度](https://pingcap.com/blog-cn/tidb-internal-3/)

TiDB 以 Region 为单位对数据进行切分,每个 Region 有大小限制(默认 96M)。Region 的切分方式是范围切分。每个 Region 会有多副本,每一组副本,称为一个 Raft Group。每个 Raft Group 中由 Leader 负责执行这块数据的读 & 写(TiDB 即将支持 [Follower-Read](https://zhuanlan.zhihu.com/p/78164196))。Leader 会自动地被 PD 组件均匀调度在不同的物理节点上,用以均分读写压力。
TiDB 以 Region 为单位对数据进行切分,每个 Region 有大小限制(默认 96M)。Region 的切分方式是范围切分。每个 Region 会有多副本,每一组副本,称为一个 Raft Group。每个 Raft Group 中由 Leader 负责执行这块数据的读 & 写(TiDB 支持 [Follower-Read](/follower-read.md))。Leader 会自动地被 PD 组件均匀调度在不同的物理节点上,用以均分读写压力。

![TiDB 数据概览](/media/best-practices/tidb-data-overview.png)

Expand Down
2 changes: 2 additions & 0 deletions best-practices/pd-scheduling-best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,5 @@ Region Merge 速度慢也很有可能是受到 limit 配置的限制(`merge-sc
没有人工介入时,PD 处理 TiKV 节点故障的默认行为是,等待半小时之后(可通过 `max-store-down-time` 配置调整),将此节点设置为 Down 状态,并开始为涉及到的 Region 补充副本。

实践中,如果能确定这个节点的故障是不可恢复的,可以立即做下线处理,这样 PD 能尽快补齐副本,降低数据丢失的风险。与之相对,如果确定这个节点是能恢复的,但可能半小时之内来不及,则可以把 `max-store-down-time` 临时调整为比较大的值,这样能避免超时之后产生不必要的副本补充,造成资源浪费。

自 v5.2.0 起,TiKV 引入了慢节点检测机制。通过对 TiKV 中的请求进行采样,计算出一个范围在 1~100 的分数。当分数大于 80 时,该节点会被设置为 Slow 状态。可以通过添加 `evict-slow-store-scheduler` 来针对慢节点进行对应的检测和调度,目前支持当且仅当出现一个慢节点时,将慢节点上的 leader 全部驱逐(其作用类似于 `evict-leader-scheduler`)。
76 changes: 70 additions & 6 deletions choose-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,83 @@ aliases: ['/docs-cn/dev/choose-index/']
## 索引的选择

TiDB 在选择索引时,会基于每个读表算子的代价估算,在此基础上提供了启发式规则 "Skyline-Pruning",以降低错误估算导致选错索引的概率
TiDB 基于规则或基于代价来选择索引。基于的规则包括前置规则和 Skyline-Pruning。在选择索引时,TiDB 会先尝试前置规则。如果存在索引满足某一条前置规则,则直接选择该索引。否则,TiDB 会采用 Skyline-Pruning 来排除不合适的索引,然后基于每个读表算子的代价估算,选择代价最小的索引

### Skyline-Pruning
### 基于规则选择

Skyline-Pruning 是一个针对索引的启发式过滤规则,评判一个索引的好坏需要从以下三个维度进行衡量:
#### 前置规则

- 选择该索引读表时,是否需要回表(即该索引生成的计划是 IndexReader 还是 IndexLookupReader)。不用回表的索引在这个维度上优于需要回表的索引。
TiDB 采用如下的启发式前置规则来选择索引:

- 选择该索引是否能满足一定的顺序。因为索引的读取可以保证某些列集合的顺序,所以满足查询要求顺序的索引在这个维度上优于不满足的索引。
+ 规则 1:如果存在索引满足“唯一性索引全匹配 + 不需要回表(即该索引生成的计划是 IndexReader)”时,直接选择该索引。

+ 规则 2:如果存在索引满足“唯一性索引 + 需要回表(即该索引生成的计划是 IndexLookupReader)”时,选择满足该条件且回表行数最小的索引作为候选索引。

+ 规则 3:如果存在索引满足“普通索引不需要回表 + 读取行数小于一定阈值”时,选择满足该条件且读取行数最小的索引作为候选索引。

+ 规则 4:如果规则 2 和 3 之中仅选出一条候选索引,则选择该候选索引。如果规则 2 和 3 均选出候选索引,则选择读取行数(读索引行数 + 回表行数)较小的索引。

上述规则中的“索引全匹配”指每个索引列上均存在等值条件。在执行 `EXPLAIN FORMAT = 'verbose' ...` 语句时,如果前置规则匹配了某一索引,TiDB 会输出一条 NOTE 级别的 warning 提示该索引匹配了前置规则。

在以下示例中,因为索引 `idx_b` 满足规则 2 中“唯一性索引 + 需要回表”的条件,TiDB 选择索引 `idx_b` 作为访问路径,`SHOW WARNING` 返回了索引 `idx_b` 命中前置规则的提示。

```sql
mysql> CREATE TABLE t(a INT PRIMARY KEY, b INT, c INT, UNIQUE INDEX idx_b(b));
Query OK, 0 rows affected (0.01 sec)

mysql> EXPLAIN FORMAT = 'verbose' SELECT b, c FROM t WHERE b = 3 OR b = 6;
+-------------------+---------+---------+------+-------------------------+------------------------------+
| id | estRows | estCost | task | access object | operator info |
+-------------------+---------+---------+------+-------------------------+------------------------------+
| Batch_Point_Get_5 | 2.00 | 8.80 | root | table:t, index:idx_b(b) | keep order:false, desc:false |
+-------------------+---------+---------+------+-------------------------+------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+-------+------+-------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+-------------------------------------------------------------------------------------------+
| Note | 1105 | unique index idx_b of t is selected since the path only has point ranges with double scan |
+-------+------+-------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```

#### Skyline-Pruning

Skyline-Pruning 是一个针对索引的启发式过滤规则,能降低错误估算导致选错索引的概率。Skyline-Pruning 从以下三个维度衡量一个索引的优劣:

- 索引的列涵盖了多少访问条件。“访问条件”指的是可以转化为某列范围的 `where` 条件,如果某个索引的列集合涵盖的访问条件越多,那么它在这个维度上更优。

对于这三种维度,如果某个索引 `idx_a`**三个维度上都不比 `idx_b`**,且**有一个维度比 `idx_b`**,那么就会优先选择 `idx_a`
- 选择该索引读表时,是否需要回表(即该索引生成的计划是 IndexReader 还是 IndexLookupReader)。不用回表的索引在这个维度上优于需要回表的索引。如果均需要回表,则比较索引的列涵盖了多少过滤条件。过滤条件指的是可以根据索引判断的 `where` 条件。如果某个索引的列集合涵盖的访问条件越多,则回表数量越少,那么它在这个维度上越优。

+ 选择该索引是否能满足一定的顺序。因为索引的读取可以保证某些列集合的顺序,所以满足查询要求顺序的索引在这个维度上优于不满足的索引。

对于以上三种维度,如果索引 `idx_a` 在这三个维度上都不比 `idx_b` 差,且有一个维度比 `idx_b` 好,那么 TiDB 会优先选择 `idx_a`。在执行 `EXPLAIN FORMAT = 'verbose' ...` 语句时,如果 Skyline-Pruning 排除了某些索引,TiDB 会输出一条 NOTE 级别的 warning 提示哪些索引在 Skyline-Pruning 排除之后保留下来。

在以下示例中,索引 `idx_b``idx_e` 均劣于 `idx_b_c`,因而被 Skyline-Pruning 排除,`SHOW WARNING` 的返回结果显示了经过 Skyline-Pruning 后剩余的索引。

```sql
mysql> CREATE TABLE t(a INT PRIMARY KEY, b INT, c INT, d INT, e INT, INDEX idx_b(b), INDEX idx_b_c(b, c), INDEX idx_e(e));
Query OK, 0 rows affected (0.01 sec)

mysql> EXPLAIN FORMAT = 'verbose' SELECT * FROM t WHERE b = 2 AND c > 4;
+-------------------------------+---------+---------+-----------+------------------------------+----------------------------------------------------+
| id | estRows | estCost | task | access object | operator info |
+-------------------------------+---------+---------+-----------+------------------------------+----------------------------------------------------+
| IndexLookUp_10 | 33.33 | 738.29 | root | | |
| ├─IndexRangeScan_8(Build) | 33.33 | 2370.00 | cop[tikv] | table:t, index:idx_b_c(b, c) | range:(2 4,2 +inf], keep order:false, stats:pseudo |
| └─TableRowIDScan_9(Probe) | 33.33 | 2370.00 | cop[tikv] | table:t | keep order:false, stats:pseudo |
+-------------------------------+---------+---------+-----------+------------------------------+----------------------------------------------------+
3 rows in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+-------+------+------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------------------------+
| Note | 1105 | [t,idx_b_c] remain after pruning paths for t given Prop{SortItems: [], TaskTp: rootTask} |
+-------+------+------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```

### 基于代价选择

Expand Down
70 changes: 70 additions & 0 deletions functions-and-operators/tidb-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,73 @@ Check Table Before Drop: false
### MySQL 兼容性
`TIDB_VERSION` 是 TiDB 特有的函数,和 MySQL 不兼容。如果要求兼容 MySQL,可以使用 `VERSION` 获取版本信息,但结果不包含详细的构建信息。
## TIDB_DECODE_SQL_DIGESTS
`TIDB_DECODE_SQL_DIGESTS` 函数用于在集群中查询一组 SQL Digest 所对应的 SQL 语句的归一化形式(即去除格式和参数后的形式)。函数接受 1 个或 2 个参数:
* `digests`:字符串类型,该参数应符合 JSON 字符串数组的格式,数组中的每个字符串应为一个 SQL Digest。
* `stmtTruncateLength`:可选参数,整数类型,用来限制返回结果中每条 SQL 语句的长度,超过指定的长度会被截断。0 表示不限制长度。
返回一个字符串,符合 JSON 字符串数组的格式,数组中的第 *i* 项为参数 `digests` 中的第 *i* 个元素所对应的语句。如果参数 `digests` 中的某一项不是一个有效的 SQL Digest 或系统无法查询到其对应的 SQL 语句,则返回结果中对应项为 `null`。如果指定了截断长度(`stmtTruncateLength > 0`),则返回结果中每条超过该长度的语句,保留前 `stmtTruncateLength` 个字符,并在尾部增加 `"..."` 后缀表示发生了截断。如果参数 `digests` 为 `NULL`,则函数的返回值为 `NULL`。
> **注意:**
>
> * 仅持有 [PROCESS](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_process) 权限的用户可以使用该函数。
> * `TIDB_DECODE_SQL_DIGESTS` 执行时,TiDB 内部从 Statement Summary 一系列表中查询每个 SQL Digest 所对应的语句,因而并不能保证对任意 SQL Digest 都总是能查询到对应的语句,只有在集群中执行过的语句才有可能被查询到,且是否能查询到受 Statement Summary 表相关配置的影响。有关 Statement Summary 表的详细说明,参见 [Statement Summary Tables](/statement-summary-tables.md)。
> * 该函数开销较大,在行数很多的查询中(比如在规模较大、比较繁忙的集群上查询 `information_schema.cluster_tidb_trx` 全表时)直接使用该函数可能导致查询运行时间较长。请谨慎使用。
> * 该函数开销大的原因是,其每次被调用时,都会在内部发起对 `STATEMENTS_SUMMARY`、`STATEMENTS_SUMMARY_HISTORY`、`CLUSTER_STATEMENTS_SUMMARY` 和 `CLUSTER_STATEMENTS_SUMMARY_HISTORY` 这几张表的查询,且其中涉及 `UNION` 操作。且该函数目前不支持向量化,即对于多行数据调用该函数时,对每行都会独立进行一次上述的查询。
### 语法图
```ebnf+diagram
DecodeSQLDigestsExpr ::=
"TIDB_DECODE_SQL_DIGESTS" "(" digests ( "," stmtTruncateLength )? ")"
```
### 示例
{{< copyable "sql" >}}
```sql
set @digests = '["e6f07d43b5c21db0fbb9a31feac2dc599787763393dd5acbfad80e247eb02ad5","38b03afa5debbdf0326a014dbe5012a62c51957f1982b3093e748460f8b00821","e5796985ccafe2f71126ed6c0ac939ffa015a8c0744a24b7aee6d587103fd2f7"]';
select tidb_decode_sql_digests(@digests);
```
```sql
+------------------------------------+
| tidb_decode_sql_digests(@digests) |
+------------------------------------+
| ["begin",null,"select * from `t`"] |
+------------------------------------+
1 row in set (0.00 sec)
```
上面的例子中,参数是一个包含 3 个 SQL Digest 的 JSON 数组,其对应的 SQL 语句分别为查询结果中给出的三项。但是其中第二条 SQL Digest 所对应的 SQL 语句未能从集群中找到,因而结果中的第二项为 `null`。
{{< copyable "sql" >}}
```sql
select tidb_decode_sql_digests(@digests, 10);
```
```sql
+---------------------------------------+
| tidb_decode_sql_digests(@digests, 10) |
+---------------------------------------+
| ["begin",null,"select * f..."] |
+---------------------------------------+
1 row in set (0.01 sec)
```
上述调用指定了第二个参数(即截断长度)为 10,而查询结果中的第三条语句的长度大于 10,因而仅保留了前 10 个字符,并在尾部添加了 `"..."` 表示发生了截断。
### MySQL 兼容性
`TIDB_DECODE_SQL_DIGESTS` 是 TiDB 特有的函数,和 MySQL 不兼容。
### 另请参阅
- [`Statement Summary Tables`](/statement-summary-tables.md)
- [`INFORMATION_SCHEMA.TIDB_TRX`](/information-schema/information-schema-tidb-trx.md)
4 changes: 2 additions & 2 deletions grafana-pd-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ aliases: ['/docs-cn/dev/grafana-pd-dashboard/','/docs-cn/dev/reference/key-monit

## Statistics - hot read

- Hot Region's leader distribution:每个 TiKV 实例上成为读取热点的 leader 的数量
- Total read bytes on hot leader Regions:每个 TiKV 实例上所有成为读取热点的 leader 的总的读取流量大小
- Hot Region's peer distribution:每个 TiKV 实例上成为读取热点的 peer 的数量
- Total read bytes on hot peer Regions:每个 TiKV 实例上所有成为读取热点的 peer 的总的读取流量大小
- Store read rate bytes:每个 TiKV 实例总的读取的流量
- Store read rate keys:每个 TiKV 实例总的读取 keys
- Hot cache read entry number:每个 TiKV 实例进入热点统计模块的 peer 的数量
Expand Down
Loading

0 comments on commit 56a2449

Please sign in to comment.