#### 15.6.2.4 InnoDB 全文索引

[](<>)[](<>)

全文索引是在基于文本的列上创建的 ([`字符`](char.html),[`VARCHAR`](char.html)， 要么[`文本`](blob.html)列）以加快对这些列中包含的数据的查询和 DML 操作。

全文索引被定义为[`创建表`](create-table.html)语句或使用添加到现有表中[`更改表`](alter-table.html)要么[`创建索引`](create-index.html).

全文搜索使用[`匹配（）...反对`](fulltext-search.html#function_match)句法。有关使用信息，请参阅[第 12.10 节，“全文搜索功能”](fulltext-search.html).

`InnoDB`全文索引在本节的以下主题下进行描述：

-   [InnoDB全文索引设计](innodb-fulltext-index.html#innodb-fulltext-index-design)

-   [InnoDB 全文索引表](innodb-fulltext-index.html#innodb-fulltext-index-tables)

-   [InnoDB 全文索引缓存](innodb-fulltext-index.html#innodb-fulltext-index-cache)

-   [InnoDB 全文索引文档\_ID 和 FTS\_文件\_ID列](innodb-fulltext-index.html#innodb-fulltext-index-docid)

-   [InnoDB全文索引删除处理](innodb-fulltext-index.html#innodb-fulltext-index-deletion)

-   [InnoDB全文索引事务处理](innodb-fulltext-index.html#innodb-fulltext-index-transaction)

-   [监视InnoDB全文索引](innodb-fulltext-index.html#innodb-fulltext-index-monitoring)

##### InnoDB全文索引设计

`InnoDB`全文索引采用倒排索引设计。反向索引存储单词列表，对于每个单词，一个单词出现在其中的文档列表。为了支持邻近搜索，还将每个单词的位置信息存储为字节偏移量。

##### InnoDB全文索引表

当`InnoDB`创建全文索引，创建一组索引表，如下例所示：

```
mysql> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200),
       FULLTEXT idx (opening_line)
       ) ENGINE=InnoDB;

mysql> SELECT table_id, name, space from INFORMATION_SCHEMA.INNODB_TABLES
       WHERE name LIKE 'test/%';
+----------+----------------------------------------------------+-------+
| table_id | name                                               | space |
+----------+----------------------------------------------------+-------+
|      333 | test/fts_0000000000000147_00000000000001c9_index_1 |   289 |
|      334 | test/fts_0000000000000147_00000000000001c9_index_2 |   290 |
|      335 | test/fts_0000000000000147_00000000000001c9_index_3 |   291 |
|      336 | test/fts_0000000000000147_00000000000001c9_index_4 |   292 |
|      337 | test/fts_0000000000000147_00000000000001c9_index_5 |   293 |
|      338 | test/fts_0000000000000147_00000000000001c9_index_6 |   294 |
|      330 | test/fts_0000000000000147_being_deleted            |   286 |
|      331 | test/fts_0000000000000147_being_deleted_cache      |   287 |
|      332 | test/fts_0000000000000147_config                   |   288 |
|      328 | test/fts_0000000000000147_deleted                  |   284 |
|      329 | test/fts_0000000000000147_deleted_cache            |   285 |
|      327 | test/opening_lines                                 |   283 |
+----------+----------------------------------------------------+-------+
```

前六个索引表包括反向索引，称为辅助索引表。当传入文档被标记化时，单个单词（也称为“标记”）连同位置信息和关联的`医生ID`.根据单词第一个字符的字符集排序权重，在六个索引表中对单词进行完全排序和分区。

反向索引被划分为六个辅助索引表，以支持并行索引创建。默认情况下，两个线程标记、排序，并将单词和相关数据插入索引表。可以使用[`innodb_ft_sort_pll_degree`](innodb-parameters.html#sysvar_innodb_ft_sort_pll_degree)变量考虑在大型表上创建全文索引时增加线程的数量。

辅助索引表名称的前缀为`fts_`并用`索引_*`#`*`.每个辅助索引表通过辅助索引表名称中与索引表匹配的十六进制值与索引表相关联`表_id`索引表的。例如`表_id`关于`测试/开启管线`桌子是`327`，其十六进制值为0x147。如前一示例所示，“147”十六进制值出现在与`测试/开启管线`桌子

一个十六进制值，表示`索引id`全文索引的名称也出现在辅助索引表名称中。例如，在辅助表名称中`测试/fts_0000000000000147_00000000000001c9_索引`，十六进制值`1c9`具有457的十进制值。上定义的索引`开放式生产线`桌子(`idx`)可以通过查询[`信息模式。INNODB_索引`](information-schema-innodb-indexes-table.html)此值的表（457）。

```
mysql> SELECT index_id, name, table_id, space from INFORMATION_SCHEMA.INNODB_INDEXES
       WHERE index_id=457;
+----------+------+----------+-------+
| index_id | name | table_id | space |
+----------+------+----------+-------+
|      457 | idx  |      327 |   283 |
+----------+------+----------+-------+
```

如果主表是在数据库中创建的，则索引表存储在它们自己的表空间中[每个表的文件数](glossary.html#glos_file_per_table)表空间。否则，索引表将存储在索引表所在的表空间中。

上例中显示的其他索引表称为通用索引表，用于删除处理和存储全文索引的内部状态。与为每个全文索引创建的反向索引表不同，这组表对于在特定表上创建的所有全文索引都是通用的。

即使删除全文索引，也会保留常用索引表。删除全文索引时`FTS_文件_ID`为索引创建的列将被保留，因为删除`FTS_文件_ID`列将需要重建以前的索引表。需要公共索引表来管理`FTS_文件_ID`柱

-   `fts已删除`和`fts_*_已删除_缓存`

    包含文档ID（DOC_ID）用于已删除但其数据尚未从全文索引中删除的文档。这个`fts_*_已删除_缓存`是的内存版本`fts已删除`桌子

-   `fts被删除`和`fts正在删除缓存`

    包含文档ID（DOC_ID）用于已删除且其数据当前正在从全文索引中删除的文档。这个`fts正在删除缓存`表是的内存版本`fts被删除`桌子

-   `fts_*_配置`

    存储有关全文索引内部状态的信息。最重要的是，它存储`FTS_同步_文档_ID`，它标识已解析并刷新到磁盘的文档。在事故恢复的情况下，`FTS_同步_文档_ID`值用于标识尚未刷新到磁盘的文档，以便可以重新解析文档并将其添加回全文索引缓存。要查看此表中的数据，请查询[`信息模式。INNODB_FT_配置`](information-schema-innodb-ft-config-table.html)桌子

##### InnoDB全文索引缓存

插入文档时，文档会被标记化，单个单词和相关数据会被插入全文索引中。这个过程，即使是对于小文档，也会导致大量小的插入到辅助索引表中，从而使对这些表的并发访问成为一个争用点。为了避免这个问题，`InnoDB`使用全文索引缓存临时缓存最近插入的行的索引表插入。这种内存缓存结构保存插入，直到缓存已满，然后将其批量刷新到磁盘（到辅助索引表）。你可以查询[`信息模式。INNODB_FT_INDEX_缓存`](information-schema-innodb-ft-index-cache-table.html)表以查看最近插入的行的标记化数据。

缓存和批处理刷新行为避免了对辅助索引表的频繁更新，这可能会在繁忙的插入和更新期间导致并发访问问题。批处理技术还避免了同一个单词的多次插入，并最大限度地减少了重复条目。不是单独刷新每个单词，而是将同一单词的插入合并并作为单个条目刷新到磁盘，从而提高插入效率，同时使辅助索引表尽可能小。

这个[`innodb_ft_缓存_大小`](innodb-parameters.html#sysvar_innodb_ft_cache_size)变量用于配置全文索引缓存大小（基于每个表），这会影响刷新全文索引缓存的频率。还可以使用[`innodb_ft_缓存总大小`](innodb-parameters.html#sysvar_innodb_ft_total_cache_size)变量

全文索引缓存存储的信息与辅助索引表相同。但是，全文索引缓存只缓存最近插入的行的标记化数据。查询时，已刷新到磁盘（到辅助索引表）的数据不会带回全文索引缓存。直接查询辅助索引表中的数据，并在返回之前将辅助索引表中的结果与全文索引缓存中的结果合并。

##### InnoDB全文索引文档\_ID和FTS\_文件\_ID列

`InnoDB`使用称为`医生ID`将全文索引中的单词映射到该单词出现的文档记录。映射需要一个`FTS_文件_ID`索引表上的列。如果`FTS_文件_ID`列未定义，`InnoDB`自动添加隐藏的`FTS_文件_ID`创建全文索引时的列。下面的示例演示了这种行为。

下表定义不包括`FTS_文件_ID`专栏：

```
mysql> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200)
       ) ENGINE=InnoDB;
```

使用在表上创建全文索引时`创建全文索引`语法，则返回一个警告，该警告报告`InnoDB`正在重建表以添加`FTS_文件_ID`柱

```
mysql> CREATE FULLTEXT INDEX idx ON opening_lines(opening_line);
Query OK, 0 rows affected, 1 warning (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 1

mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------+
| Level   | Code | Message                                          |
+---------+------+--------------------------------------------------+
| Warning |  124 | InnoDB rebuilding table to add column FTS_DOC_ID |
+---------+------+--------------------------------------------------+
```

使用时会返回相同的警告[`改变桌子`](alter-table.html)将全文索引添加到没有`FTS_文件_ID`柱如果在以下位置创建全文索引：[`创建表格`](create-table.html)时间，不指定时间`FTS_文件_ID`柱`InnoDB`添加隐藏的`FTS_文件_ID`列，没有警告。

定义`FTS_文件_ID`列在[`创建表格`](create-table.html)与在已加载数据的表上创建全文索引相比，时间成本更低。如果`FTS_文件_ID`列是在加载数据之前在表上定义的，不必重建表及其索引来添加新列。如果你不关心`创建全文索引`性能，省去`FTS_文件_ID`专栏`InnoDB`为你创造它。`InnoDB`创建隐藏的`FTS_文件_ID`列以及唯一索引(`FTS_文件_ID_索引`)在`FTS_文件_ID`柱如果你想创造自己的`FTS_文件_ID`列，该列必须定义为`BIGINT UNSIGNED NOT NULL`并命名为`FTS_文件_ID`（全部大写），如下例所示：

笔记

这个`FTS_文件_ID`列不需要定义为`自动增量`列，但这样做可以使加载数据更容易。

```
mysql> CREATE TABLE opening_lines (
       FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200)
       ) ENGINE=InnoDB;
```

如果你选择定义`FTS_文件_ID`列本身，您负责管理列以避免空值或重复值。`FTS_文件_ID`值不能重用，这意味着`FTS_文件_ID`价值观必须不断增长。

或者，您可以创建所需的唯一`FTS_文件_ID_索引`（全部大写）在`FTS_文件_ID`柱

```
mysql> CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on opening_lines(FTS_DOC_ID);
```

如果不创建`FTS_文件_ID_索引`, `InnoDB`自动创建它。

笔记

`FTS_文件_ID_索引`无法定义为降序索引，因为`InnoDB`SQL解析器不使用降序索引。

使用的最大值之间的允许间隙`FTS_文件_ID`价值与新`FTS_文件_ID`值为65535。

为了避免重建表`FTS_文件_ID`删除全文索引时将保留列。

##### InnoDB全文索引删除处理

删除具有全文索引列的记录可能会导致辅助索引表中出现大量小的删除，从而使并发访问这些表成为一个争用点。为了避免这个问题`医生ID`已删除文档的备份将记录在特殊日志中`FTS已删除`每当从索引表中删除一条记录时，该索引记录仍保留在全文索引中。在返回查询结果之前`FTS已删除`表用于筛选已删除的`医生ID`s、 这种设计的好处是删除速度快且成本低。缺点是删除记录后索引的大小不会立即减小。要删除已删除记录的全文索引项，请运行`优化表格`在带索引的表上[`innodb_optimize_fulltext_only=ON`](innodb-parameters.html#sysvar_innodb_optimize_fulltext_only)重建全文索引。有关更多信息，请参阅[优化InnoDB全文索引](fulltext-fine-tuning.html#fulltext-optimize).

##### InnoDB全文索引事务处理

`InnoDB`全文索引由于其缓存和批处理行为而具有特殊的事务处理特性。具体来说，全文索引上的更新和插入是在事务提交时处理的，这意味着全文搜索只能看到提交的数据。下面的示例演示了这种行为。全文搜索仅在提交插入的行后返回结果。

```
mysql> CREATE TABLE opening_lines (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500),
       author VARCHAR(200),
       title VARCHAR(200),
       FULLTEXT idx (opening_line)
       ) ENGINE=InnoDB;

mysql> BEGIN;

mysql> INSERT INTO opening_lines(opening_line,author,title) VALUES
       ('Call me Ishmael.','Herman Melville','Moby-Dick'),
       ('A screaming comes across the sky.','Thomas Pynchon','Gravity\'s Rainbow'),
       ('I am an invisible man.','Ralph Ellison','Invisible Man'),
       ('Where now? Who now? When now?','Samuel Beckett','The Unnamable'),
       ('It was love at first sight.','Joseph Heller','Catch-22'),
       ('All this happened, more or less.','Kurt Vonnegut','Slaughterhouse-Five'),
       ('Mrs. Dalloway said she would buy the flowers herself.','Virginia Woolf','Mrs. Dalloway'),
       ('It was a pleasure to burn.','Ray Bradbury','Fahrenheit 451');

mysql> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line) AGAINST('Ishmael');
+----------+
| COUNT(*) |
+----------+
|        0 |
+----------+

mysql> COMMIT;

mysql> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line) AGAINST('Ishmael');
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
```

##### 监视InnoDB全文索引

[](<>)[](<>)

您可以监视和检查`InnoDB`通过查询以下内容创建全文索引`信息模式`桌子：

-   [`INNODB_FT_配置`](information-schema-innodb-ft-config-table.html)

-   [`INNODB_FT_INDEX_表`](information-schema-innodb-ft-index-table-table.html)

-   [`INNODB_FT_INDEX_缓存`](information-schema-innodb-ft-index-cache-table.html)

-   [`INNODB_FT_DEFAULT_STOPWORD`](information-schema-innodb-ft-default-stopword-table.html)

-   [`INNODB_FT_删除`](information-schema-innodb-ft-deleted-table.html)

-   [`INNODB_FT_被删除`](information-schema-innodb-ft-being-deleted-table.html)

    还可以通过查询查看全文索引和表的基本信息[`INNODB_索引`](information-schema-innodb-indexes-table.html)和[`INNODB_表`](information-schema-innodb-tables-table.html).

    有关更多信息，请参阅[第15.15.4节，“InnoDB信息\_“模式全文索引表”](innodb-information-schema-fulltext_index-tables.html).
