Skip to content

Commit

Permalink
sql-statements, tidb-configuration-file: refine the document about ex…
Browse files Browse the repository at this point in the history
…pression index (pingcap#6643)
  • Loading branch information
wjhuang2016 authored Aug 13, 2021
1 parent 76a6118 commit fc85fca
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 19 deletions.
88 changes: 78 additions & 10 deletions sql-statements/sql-statement-create-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,39 +151,105 @@ Query OK, 0 rows affected (0.31 sec)

## 表达式索引

在一些场景中,查询的条件往往是基于某个表达式进行过滤。在这些场景中,一般的索引不能生效,执行查询只能遍历整个表,导致查询性能较差。表达式索引是一种特殊的索引,能将索引建立于表达式上。在创建了表达式索引后,基于表达式的查询便可以使用上索引,极大提升查询的性能。

假设要基于 `col1+cols2` 这个表达式建立索引,示例的 SQL 语句如下:

{{< copyable "sql" >}}

```sql
CREATE INDEX idx1 ON t1 ((col1 + col2));
```

或者等价的语句:

{{< copyable "sql" >}}

```sql
ALTER TABLE t1 ADD INDEX idx1((col1 + col2));
```

还可以在建表的同时指定表达式索引:

{{< copyable "sql" >}}

```sql
CREATE TABLE t1(col1 char(10), col2 char(10), key index((col1 + col2)));
```

删除表达式索引与删除普通索引的方法一致:

{{< copyable "sql" >}}

```sql
DROP INDEX idx1 ON t1;
```

> **注意:**
>
> 该功能目前为实验特性,不建议在生产环境中使用。
> 表达式索引不能为主键。
>
> 表达式索引中的表达式不能包含以下内容:
>
> - 易变函数,例如 `rand()``now()` 等。
> - 系统变量以及用户变量。
> - 子查询。
> - AUTO_INCREMENT 属性的列。一个例外是设置系统变量 `tidb_enable_auto_increment_in_generated``true` 后,可以去掉该限制。
> - 窗口函数。
> - row 函数。例如 `create table t (j json, key k (((j,j))));`
> - 聚合函数。
>
> 表达式索引将隐式占用名字,`_V$_{index_name}_{index_offset}`,如果已有相同名字的列存在,创建表达式索引将报错。如果后续新增相同名字的列,也会报错。
>
> 表达式中的表达式中出现函数参数的个数必须正确。
当查询语句中的表达式与表达式索引中的表达式一致时,优化器可以为该查询选择使用表达式索引。依赖于统计信息,某些情况下优化器不一定选择表达式索引。这时可以通过 hint 指定强制使用表达式索引。

在以下示例中,假设建立在 `lower(col1)` 表达式上的索引为 `idx`

如果需要使用这一特性,在 [TiDB 配置文件](/tidb-configuration-file.md#allow-expression-index-从-v400-版本开始引入)中进行以下设置
当读取的结果为相同的表达式时,可以使用表达式索引。例如

{{< copyable "sql" >}}

```sql
allow-expression-index = true
SELECT lower(col1) FROM t;
```

TiDB 不仅能将索引建立在表中的一个或多个列上,还可以将索引建立在一个表达式上。当查询涉及表达式时,表达式索引能够加速这些查询。
当过滤的条件中有相同的表达式时,可以使用表达式索引。例如:

考虑以下查询:
{{< copyable "sql" >}}

```sql
SELECT * FROM t WHERE lower(col1) = "a";
SELECT * FROM t WHERE lower(col1) > "a";
SELECT * FROM t WHERE lower(col1) BETWEEN "a" AND "b";
SELECT * FROM t WHERE lower(col1) in ("a", "b");
SELECT * FROM t WHERE lower(col1) > "a" AND lower(col1) < "b";
SELECT * FROM t WHERE lower(col1) > "b" OR lower(col1) < "a";
```

当查询按照相同的表达式进行排序时,可以使用表达式索引。例如:

{{< copyable "sql" >}}

```sql
SELECT * FROM t WHERE lower(name) = "pingcap";
SELECT * FROM t ORDER BY lower(col1);
```

如果建立了如下的表达式索引,就可以使用索引加速以上查询
当聚合函数或者 `GROUP BY` 中包含相同的表达式时,可以使用表达式索引。例如

{{< copyable "sql" >}}

```sql
CREATE INDEX idx ON t ((lower(name)));
SELECT max(lower(col1)) FROM t;
SELECT min(col1) FROM t GROUP BY lower(col1);
```

要查看表达式索引对应的表达式,可执行 `show index` 或查看系统表 `information_schema.tidb_indexes` 以及 `information_schema.STATISTICS` 表,输出中 `Expression` 这一列显示对应的表达式。对于非表达式索引,该列的值为 `NULL`

维护表达式索引的代价比一般的索引更高,因为在插入或者更新每一行时都需要计算出表达式的值。因为表达式的值已经存储在索引中,所以当优化器选择表达式索引时,表达式的值就不需要再计算。因此,当查询速度比插入速度和更新速度更重要时,可以考虑建立表达式索引。

表达式索引的语法和限制与 MySQL 相同,是通过将索引建立在隐藏的虚拟生成列 (generated virtual column) 上来实现的。因此所支持的表达式继承了虚拟生成列的所有[限制](/generated-columns.md#生成列的局限性)目前,建立了索引的表达式只有在 `FIELD` 子句、`WHERE` 子句和 `ORDER BY` 子句中时,优化器才能使用表达式索引。后续将支持 `GROUP BY` 子句。
表达式索引的语法和限制与 MySQL 相同,是通过将索引建立在隐藏的虚拟生成列 (generated virtual column) 上来实现的。因此所支持的表达式继承了虚拟生成列的所有[限制](/generated-columns.md#生成列的局限性)

## 不可见索引

Expand All @@ -198,13 +264,15 @@ CREATE UNIQUE INDEX c1 ON t1 (c1) INVISIBLE;

## 相关系统变量

`CREATE INDEX` 语句相关的系统变量有 `tidb_ddl_reorg_worker_cnt``tidb_ddl_reorg_batch_size``tidb_ddl_reorg_priority`,具体可以参考[系统变量](/system-variables.md#tidb_ddl_reorg_worker_cnt)
`CREATE INDEX` 语句相关的系统变量有 `tidb_ddl_reorg_worker_cnt``tidb_ddl_reorg_batch_size` `tidb_ddl_reorg_priority` `tidb_enable_auto_increment_in_generated`,具体可以参考[系统变量](/system-variables.md#tidb_ddl_reorg_worker_cnt)

## MySQL 兼容性

* 不支持 `FULLTEXT``HASH``SPATIAL` 索引。
* 不支持降序索引 (类似于 MySQL 5.7)。
* 无法向表中添加 `CLUSTERED` 类型的 `PRIMARY KEY`。要了解关于 `CLUSTERED` 主键的详细信息,请参考[聚簇索引](/clustered-indexes.md)
* 表达式索引与视图存在兼容性问题。通过视图进行查询时,无法使用上表达式索引。
* 表达式索引与 Binding 存在兼容性问题。当表达式索引中的表达式存在常量时,对应查询所建的 Binding 会扩大范围。假设表达式索引中的表达式为 `a+1`,对应的查询条件为 `a+1 > 2`。则建立的 Binding 为 `a+? > ?`,这会导致像 `a+2 > 2` 这样的查询也会强制使用表达式索引,得到一个较差的执行计划。这同样影响 SQL Plan Management (SPM) 中的捕获和演进功能。

## 另请参阅

Expand Down
6 changes: 6 additions & 0 deletions system-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,12 @@ MPP 是 TiFlash 引擎提供的分布式计算框架,允许节点之间的数
> - 启用 TiDB Binlog 后,开启该选项无法获得性能提升。要获得性能提升,建议使用 [TiCDC](/ticdc/ticdc-overview.md) 替代 TiDB Binlog。
> - 启用该参数仅意味着 Async Commit 成为可选的事务提交模式,实际由 TiDB 自行判断选择最合适的提交模式进行事务提交。

### `tidb_enable_auto_increment_in_generated`

- 作用域:SESSION | GLOBAL
- 默认值:`OFF`
- 这个变量用于控制是否允许在创建生成列或者表达式索引时引用自增列。

### `tidb_enable_cascades_planner`

- 作用域:SESSION | GLOBAL
Expand Down
9 changes: 0 additions & 9 deletions tidb-configuration-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -643,12 +643,3 @@ TiDB 服务状态相关配置。

+ 控制 [`INFORMATION_SCHEMA.DEADLOCKS`](/information-schema/information-schema-deadlocks.md) 表中是否收集可重试的死锁错误信息。详见 `DEADLOCKS` 表文档的[可重试的死锁错误](/information-schema/information-schema-deadlocks.md#可重试的死锁错误)小节。
+ 默认值:false

## experimental

experimental 部分为 TiDB 实验功能相关的配置。该部分从 v3.1.0 开始引入。

### `allow-expression-index` <span class="version-mark">从 v4.0.0 版本开始引入</span>

+ 用于控制是否能创建表达式索引。
+ 默认值:false

0 comments on commit fc85fca

Please sign in to comment.