Files
rikako-note/mysql/mysql文档/mysql_索引.md
2025-02-19 20:47:10 +08:00

33 KiB
Raw Blame History

innodb索引与算法

innodb存储引擎支持如下集中常见的索引

  • B+树索引
    • 对于B+树索引,其只能找到被查找数据所在的页,然后数据库把页读入到内存中,再在内存中进行查找
  • 全文索引
  • 哈希索引
    • innodb中哈希索引是自适应的innodb存储引擎会根据目前表的使用情况自动生成哈希索引

索引算法

二分查找

如前所示mysql数据页中存在page directory而page directory中slots是按照主键顺序来进行排放的。

对于数据的查找是通过对page directory中的槽进行二分查找得到的

B+树索引

inoodb中索引大多是B+树的实现,且具有高扇出的特性。故而,在数据库中,B+树的高度一般都在2~4层即在查找某一行记录时最多只需要2~4次IO。

innodb中B+树索引可以分为聚簇索引和辅助索引其都是基于B+树实现,所有的数据都存放在叶子节点中

聚簇索引和辅助索引的区别在于叶子节点中是否存放的是整行的记录信息。

聚簇索引

在innodb中表是由索引组织的即表中的数据按照主键的顺序存放。

聚簇索引是按照每张表的主键构建一颗B+树,而叶子节点存放的则是整张表的行记录数据,故而,聚簇索引的叶子节点也被称为数据页

和B+树一样,每个数据页(叶子节点)都通过双向链表来进行链接。

每张表只能拥有一个聚簇索引,并且,在多数情况下,查询优化器倾向于采用聚簇索引。因为聚簇索引能够直接在叶子节点获取到行记录。

非数据页

在非数据页中存放的是key以及指向数据页的页号。

聚簇索引的存储并非是物理上连续的,而是通过双向链表来维护逻辑上的顺序

数据页与数据页之间通过双向链表来维护顺序排序,而位于同一个页中的记录之间也是通过双向链表来维护排序的。

对于聚簇索引,其按照主键排序进行查找按主键进行范围查找时,查询速度很快。

辅助索引

对于辅助索引叶子节点并不包含行记录的全部数据。在辅助索引的叶子节点中叶子节点除了包含辅助索引的key外每个叶子节点中的索引行还包含一个书签bookmark。bookmark可以告知inodb存储引擎哪里能找到和索引相对应的行数据。

实际上innodb存储引擎的辅助索引其bookmark就是相应行数据的聚簇索引key`。

辅助索引并不会影响行数据在聚簇索引上的组织,故而每张表可以含有一个聚簇索引和多个辅助索引。

辅助索引查找

当通过辅助索引来查找数据时innodb会遍历辅助索引的B+树数据结构,并从叶子节点中获取指向的主键索引值,之后再通过主键索引来查找到完整的行记录。

辅助索引查找分析

如果聚簇索引和辅助索引的B+树高度同样为3那么当根据辅助索引来查找关联的主键时需要花费3次IO。此时再根据主键来从聚簇索引中获取对应行数据需要另外3次IO。

故而根据辅助索引来获取行记录大概需要6次IO。

索引创建

通过alter table语法可以选择索引的创建方式

alter table tbl_name 
| add {index|key} [index_name]
[index_type] (index_col_name, ...)
algorithm [=] {default|inplace|copy}
lock [=] {default|none|shared|exclusive}

algorithm

通过algorithm可以指定创建或删除索引的算法:

  • copy通过创建临时表的方式定义新的表结构并将原表中的数据移动到新的表最后删除原表并将临时表重命名
    • 该算法将会耗费大量事件,并且在执行时表不可被访问
  • inplace索引创建和删除操作不采用临时表
  • default: 按照old_alter_table参数来判断是通过inplace还是copy来创建或删除索引默认old_alter_table为off即是采用inplace算法

lock

lock部分代表索引创建或删除时对表的加锁情况

  • none执行索引的创建或删除操作时对目标表不添加任何的锁在执行过程中事务仍然能够进行读写操作不会阻塞。该加锁情况能够获取最大程度的并发度
  • share在执行过程中对表添加s锁s锁会和x锁以及ix锁发生冲突但是能够兼容s锁和is锁
    • 故而在加锁方式为share的场景下执行索引的创建或删除时其他事务仍然能够执行读取操作但是写操作则是会被阻塞。
    • 如果存储引擎不支持share模式会返回相应的错误信息
  • exclusive在exclusive模式下执行索引的创建和删除操作时会对目标表添加一个x锁此时其他事务对该表的读和写操作都不会被执行
  • default
    • default模式下首先会判断当前操作能否使用none
    • 如果不能则判断是否能够使用shared
    • 如果仍然不能那么最后会判断能否使用exclusive

online DDL

innodb存储引擎实现online DDL的原理是在执行索引的创建或删除操作时insert, update, delete这些DML写操作的日志写入到一个缓存中等到索引创建完成后再将这些DML语句重做到表上日志内容类似于redo log

该缓存的大小可以通过innodb_online_alter_log_max_size来进行控制,默认大小为128M

如果再执行索引创建和更新的表比较大,并且在online alter执行过程中存在大量的写事务,那么当innodb_online_alter_log_max_size指定的空间不足以存放时,会抛出错误。

如果发生上述错误,可以考虑增加inodb_online_alter_log_max_size参数的值;也可以设置alter tablelock模式为share那么在执行过程中不会有写事务的发生不需要进行DML日志的记录。

Cardinality

并不是所有的字段都适合创建B+树索引。例如对于性别字段、类型字段等它们的选择范围都很小这种字段不适合创建B+树索引。

性别字段中只有MF两种可选值,故而执行select * from student where sex = 'F'这类sql可能会得到表中50%的数据这种情况下为性别字段添加B+树索引完全没有必要。

而对于bigint类型的id字段其选择范围很广且没有重复这类字段适合使用B+树索引。

Cardinality

通过show index语句可以查看索引是否拥有高选择性,Cardinality列代表索引中不重复记录数量的预估值

Cardinality是一个预估值,并不是准确的值,且Cardinality / rows_in_table的值应该尽可能的接近1。如果该值非常小那么用户应考虑该索引的创建是否有必要。

innodb存储引擎的Cardinality

在生产环境下索引的操作可能十分频繁如果每次操作都对cardinality进行统计那么将会带来巨大的开销。故而数据库针对Cardinality的统计都是通过采样来进行的

在innodb中针对cardinality统计信息的更新发生在两个操作中insert, update。innodb针对cardinality的更新策略为

  • 表中1/16的数据已经发生变化
    • 自上一次统计cardinality信息时起表中1/16的数据已经发生过变化此时需要重新统计cardinality
  • stat_modified_counter >= 2000,000,000
    • 如果针对表中某一行数据进行频繁的更新那么该场景不会适配第一种更新策略故而在innodb内部维护了一个计数器stat_modified_counter用于标识发生变化的次数当计数器的值大于2000,000,000也需要更新cardinality

Cardinality采样

默认情况下innodb会针对8个叶子节点进行采样采样过程如下

  • 取得B+树索引中叶子节点的数量记为A
  • 随机获取索引8个叶子节点统计每个页不同记录的个数记为P1, P2, ... , P8
  • 根据采样信息给出Cardinality的预估值(P1 + P2 + ... + P8) * A/8

索引使用

联合索引

联合索引代表对表上的多个列进行索引。

示例如下:

create table t (
    id bigint not null auto_increment,
    a int not null,
    b int not null,
    primary key(id),
    index idx_a_b (a, b)
);

对于上述联合索引(a,b),各查询语句使用索引的情况如下:

  • where a = xxx and b = xxx
    • 该语句会使用联合索引
  • where a = xxx
    • 该语句同样可以使用联合索引
  • where b = xxx:
    • 该语句无法使用联合索引

覆盖索引

innodb存储引擎支持覆盖索引即通过辅助索引即可得到查询记录无需再次查询聚簇索引。

通常来说,辅助索引中叶子节点的记录大小要远小于聚簇索引中叶子节点的记录大小。故而,在范围统计的场景下(select count(1)),辅助索引叶子节点中,一个页包含更多的记录,表扫描时需要读取的页数页更少。

故而在部分场景下使用覆盖索引能够节省大量的io操作。

对于辅助索引而言,其叶子节点的记录中包含(primary key1, primary key2, ..., key1, key2)等信息,故而,如下语句都可以通过一次辅助联合索引查询来完成:

  • select key2 from table where key1 = xxx
    • 会命中辅助索引且辅助索引中包含key2的值故而无需再次查询聚簇索引
  • select primary key2,key2 from table where key1 = xxx
  • select primary key1,key2 from table where key1 = xxx
  • select primary key1, primary key2, key2 from key1 = xxx

覆盖索引对于统计场景的好处

例如对于表buy_log

create table buy_log (
    userid int unsigned not null,
    buy_date date,
    index `idx_userid` (userid),
    index `idx_userid_buy_date` (userid, buy_date)
);

预置如下数据:

insert into buy_log(userid, buy_date)
values (1, '2022-01-01'),
       (2,'2022-03-04'),
       (3, '2024-12-31'),
       (4, '2024-07-11'),
       (5, '2025-01-01');

执行explain select count(*) from buy_log;语句时由于where条件为空其并不会命中索引但是语句执行的结果如下所示

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE buy_log null index null idx_userid 4 null 5 100 Using index

上述返回结果中,possible_keys列为null但是实际执行时优化器却选择了idx_userid索引Extra列值为Using index,代表优化器选择了覆盖索引。

由于覆盖索引中记录大小更小故而使用覆盖索引能够节省io提升性能。

并且,对于explain select count(*) from buy_log where buy_date >= '2023-01-01' and buy_date <= '2024-01-01';语句,其返回结果如下

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE buy_log null index idx_userid_buy_date idx_userid_buy_date 8 null 5 20 Using where; Using index

正常来说,idx_userid_buy_date索引组成为(userid, buy_date),当根据buy_date来进行查找时,不应该命中索引。

但是,由于辅助索引中同一页包含记录更多,故而上述语句仍然使用了idx_userid_buy_date覆盖索引。

优化器选择不使用索引

在某些情况下当使用explain语句进行分析时会发现优化器没有选择索引去查找数据而是通过全盘扫描聚簇索引。这种情况通常发生在范围查找join连接等操作时。

辅助索引不能覆盖

对于辅助索引不能进行覆盖的场景,优化器仅当查询少量数据时选择辅助索引。

优化器不选择辅助索引的原因是,根据辅助索引再次查询聚簇索引时,会带来大量的随机读。由于辅助索引和聚簇索引的排序不同在辅助索引中连续的数据很可能在聚簇索引中是分散的。如果使用辅助索引那么在根据主键查询聚簇索引时可能带来大量的随机读主键可能随机分布在各个数据页中这样会带来大量的io。

故而,当辅助索引需要读取大量的记录,并且辅助索引不能覆盖时,优化器会倾向直接在聚簇索引中进行顺序查找。顺序读通常要远快于随机读。

如果mysql server实例部署在固态硬盘上随机读取的速度很快同时确认使用辅助索引的性能更佳可以使用force index来强制使用某个索引,使用示例如下:

select * from orderdetails force index (orderID) where orderid > 10000 and order id < 102000

索引提示

mysql支持索引提示如下两种场景可能会用到索引提示

  • mysql错误的选择了某个索引导致sql语句运行较慢
  • 某个sql可选择索引非常多此时优化器选择执行计划的耗时可能大于sql语句执行的耗时

mysql数据库中索引提示的语法如下

table_name [[as] alias] [index_hint_list]

-- 其中index_hint_list的含义如下
index_hint_list:
index_hint[, index_hint]...

-- index_hint的含义则如下
index_hint:
USE {INDEX|KEY}
[{FOR {JOIN | ORDER BY | GROUP BY}}] ([index_list])

| IGNORE {INDEX | KEY}
[{FOR {JOIN | ORDER BY | GROUP BY}}] (index_list)

| FORCE {INDEX|KEY}
[{FOR {JOIN | ORDER BY | GROUP BY}}] (index_list)

-- index_list含义如下
index_list:
index_name, [, index_name]...

创建t_demo示例如下:

create table t_demo (
    a int not null,
    b int not null,
    key idx_a (a),
    key idx_b (b)
);

insert into t_demo(a,b)
values
    (1,1),
    (1,2),
    (2, 3),
    (2, 4),
    (1,2);

Use index

执行如下语句explain select * from t_demo where a=1 and b = 2;,其返回执行计划如下:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t_demo null index_merge idx_a,idx_b idx_b,idx_a 4,4 null 1 83.33 Using intersect(idx_b,idx_a); Using where; Using index

易知优化器选择了使用idx_aidx_b两个索引来完成该查询且Extra列包含了Using intersect(b,a),代表查询结果根据两个索引得到的结果进行求交集的数学运算。

可以通过Use Index来提示使用idx_a索引:

explain select * from t_demo use index (idx_a) where a=1 and b = 2;

得到结果如下:

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t_demo null ref idx_a idx_a 4 const 3 20 Using where

上述结果显示执行方案选用了idx_a

在使用use index语法之后,仍然有可能出现优化器没有使用该索引的情况,此时可以使用force index语法,来强制指定使用的索引。

Multi-Range Read

mysql支持Multi-Range Read优化用于减少随机的磁盘访问将随机访问转化为较为顺序的数据访问。对于io-bound的sql查询其能带来性能的较大提升。

mutli-range read优化适用于range, ref, eq_ref类型的查询。

multi-range read优势

  • MRR能够令数据访问变得较为顺序在查询辅助索引时对于得到的查询结果按照主键进行排序并按照主键排序的顺序进行书签查找
  • 减少缓冲池中页被替换的次数
  • 批量处理对于key的查询操作

范围查询和join查询优化

对于innodb的范围查询和join查询MRR工作方式如下

  • 将查询到的辅助索引键值存放在缓冲中,此时缓存中的数据按照辅助索引排序
  • 将缓存中的键值按照rowId进行排序
  • 根据rowId的排序来实际访问数据文件

当innodb的缓冲池不足以存放表中所有数据时频繁的离散读写会导致缓冲池中的页被换出又被不断读入。

如果按照主键顺序进行访问,可以将该类行为降至最低,页面不会被换出缓冲区后又被读入

拆分键值对

除了上述优化外对某些范围查询mrr还能够进行拆分优化这样在拆分过程中直接能过滤掉一些不符合查询条件的数据。

例如:

select * from t where key_part1 >= 1000 and key_part1 < 2000 and key_part2 = 1000;

表t存在(key_part1, key_part2)的联合索引。

未开启MRR

如果未开启mrr那么此时查询类型为RANGEmysql优化器会将key_part位于[1000, 2000)范围内的全部数据都取出即是key_part2不为1000。在去除后再按key_part2条件对取出数据进行过滤。

这将会导致有大量无用数据被取出。如果存在大量数据且key_part2不为1000那么使用mrr将会有大量性能提升。

开启MRR优化

在使用了MRR优化后优化器会先对查询条件进行拆分key_part1 >= 1000 and key_part1 < 2000 and key_part2 = 1000条件拆分为(1000, 1000), (1001, 1000), ..., (1999, 1000),在根据拆分后的条件进行查询。

mrr控制

是否开启mrr可以通过参数optimizer_switch中的flag来控制当mrr为on代表启用mrr优化。

mrr_cost_based标记代表是否通过cost based的方式来选择是否启用mrr

如果将mrr设置为onmrr_cost_based设置为off代表总是启用mrr优化。

read_rnd_buffer_size

read_rnd_buffer_size用来控制键值的缓冲区大小当大于该值时则执行器则对已经缓存的数据根据rowId来进行排序并通过rowId来获取数据。该值默认为256K.

Index Condition Pushdown(ICP)

可以通过optimizer_switch中的flag来控制ICP是否开启,如index_condition_pushdownon代表icp开启。

例如,表people包含zip_code, last_name, first_name)索引,执行如下语句

select * from people where zipcode = '95054' and last_name like '%asahi%' and address like '%street%';

关闭ICP

如果ICP优化没有开启那么数据库首先会根据索引查询zipcode为95054的记录然后查询出后再根据查询出的结果过滤where的后两个条件last_name like '%asahi%' and address like '%street%'

开启ICP

当开启ICP后数据库会将where的部分过滤条件放在存储引擎层在索引获取数据同时就会进行where条件的过滤。

innodb hash

在innodb中采用除法散列的哈希方法通过k % m将关键字k映射到m个槽中的一个,即

hash(k) = k % m

innodb中的哈希

innodb存储引擎采用哈希算法对字典进行查找冲突机制采用链表方式哈希函数采用k % m的方式进行散列。

对于缓冲池页的哈希表缓冲池中的page页都有一个chain指针指向相同哈希值的页。而对于m的取值,其规则如下:

  • m的取值应略大于2倍的缓冲池页数量的质数
    • 例如,若innodb_buffer_pool_size大小为10M那么缓冲池页数量为 10 * 1024 / 16 = 640可容纳240个缓冲页故而对于缓冲池页内存的哈希表来说需要分配的槽个数m为大于640 * 2的质数,即1399

自适应hash索引

自适应hash索引可以通过参数innodb_adaptive_hash_index来进行开启或关闭并且自适应hash索引的使用情况可以通过show engine innodb status来进行查看:

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
0.00 hash searches/s, 320660.58 non-hash searches/s

可以根据hash searches/snon-hash searches/s来查看自适应hash索引的使用情况。

全文检索

倒排索引

全文检索通常使用倒排索引(inverted index)来实现和B+树索引一致,倒排索引也是一种索引结构。

倒排索引在辅助表(auxiliary table)中存储了单词单词自身在一个或多个文档中所在位置之间的映射关系。通常,倒排索引通过关联数组可以实现,拥有两种表现形式:

  • inverted file index: {单词单词所在文档id}
  • full inverted index: {单词, (单词所在文档id, 在文档中的具体位置)}

inverted file index

对于inverted file index其存储的数据结构如下所示

Number Text Documents
1 code 1,4
2 days 3,6
3 hot 1,4

其中,Documents存储的是包含查询关键字的文档id数组。

对于inverted file index其仅保存文档的id

full inverted index

对于full inverted index其存储的是(文档id文档中位置)pair

full inverted index的存储结构示例如下所示;

Number Text Documents
1 code (1:6), (4:8)
2 days (3:2), (6:2)
3 hot (1:3), (4:4)

full inverted index 相较于 inverted file index除了存储文档id之外还存储单词所在文档的位置信息。

innodb全文检索

innodb支持full inverted index形式的全文检索。

在innodb中(DocumentId, Position)视为ilist。故而,在全文检索的表中,存在两个字段,wordilist,并在word字段设有索引。并且innodb在ilist中存放了position信息故而可以支持proximity search

辅助表

innodb中倒排索引需要将word存放在辅助表中,并且,为了提高全文检索的并行能力,共存在6张辅助表每张表根据word的Latin进行分区。

辅助表为持久化的表,存放在磁盘中。

FTS Index Cache (全文检索索引缓存)

FTS Index Cache为红黑树结构根据(word, ilist)进行排序。

在插入数据时,即使插入数据已经更新了对应的数据库表,但是对全文索引更新可能仍位于FTS Index Cache即辅助表尚未被更新。Innodb会批量对辅助表进行更新而非每次插入后都立即更新索引表。

当对全文检索进行查询时辅助表首先会将FTS Index Cache中对应word字段合并到辅助表中然后再在辅助表中执行查询操作。

上述FTS Index Cache操作类似Insert Buffer其能提高innodb的性能并且其由红黑树排序后再执行批量插入其产生的辅助表相对较小。

查看指定倒排索引的辅助表分词信息

innodb允许用户查看指定倒排索引辅助表的分词信息可以通过设置innodb_ft_aux_table来查看倒排索引的辅助表。

set global innodb_ft_aux_table='{schema_name}/{table_name}';

执行完上述语句后,可以在information_schema.innodb_ft_index_table中查询表的分词信息。

FTS Index Cache更新和写盘时机

Innodb在事务提交时将分词写入到FTS Index Cache中,然后再根据批量更新将FTS Index Cache写入到磁盘。

在事务提交时FTS Index Cache中数据会同步到磁盘的辅助表中。但是当数据库发生宕机时FTS Index Search中的数据可能尚未被同步到磁盘中。

在上述宕机情况下下次数据库重启时若用户对表进行全文检索操作插入或查询innodb会自动读取未完成的文档并然后进行分词操作再次将分词结果放入到FTS Index Cache中。

分词删除

对于文档中分词的删除操作,在事务提交时,不删除辅助表中的数据,而只是删除FTS Index Cache中的记录。对于被删除的记录会根记录其FTS Dcoument Id并且将该id保存在deleted辅助表中。

在删除文档时,文档内容从一般表中被删除,但是索引辅助表中的数据并不会被删除,相反的,还会将FTS_DOC_ID添加到deleted辅助表中。

OPTIMIZE TABLE

由上述内容可知对文档的DML并不会实际删除索引中的数据,只是会在deleted辅助表中添加FTS_DOC_ID,故而在应用程序运行时,索引会变得越来越大

mysql允许通过optimize table命令来实际将已删除记录从索引中删除。

由于optimize table语句不仅会删除索引中的数据,还会执行其他操作,例如Cardinality重新统计等。

如果用户仅希望对倒排索引进行操作,可以设置innodb_optimize_fulltext_only参数。

可以执行如下语句

set global innodb_optimize_fulltext_only=1;
optimize table xxx;

如果被删除文档很多那么optimize table可能会花费大量时间这将对程序的运行造成影响。

用户可以通过参数innodb_ft_num_word_optimize来限制每次实际删除的分词数量该参数默认值为2000.

innodb_ft_cache_size

可以通过innodb_ft_cache_size来控制FTS Index Cache的大小默认大小为32M。当缓冲被填满后,会将缓存中(word, ilist)数据同步到位于磁盘的辅助表中。

适当增加innodb_ft_cache_size参数的值能够提升全文检索的性能,但是在宕机时,位同步到磁盘中的数据可能需要更长时间来进行恢复。

FTS Document id

在innodb存储引擎中为了支持全文检索必须存在一个字段和辅助表中的word进行对应。在innodb中对应字段为FTS_DOC_ID

FST_DOC_ID字段的字段类型必须为BIGINT UNSIGNED NOT NULL并且innodb存储引擎会自动为该列添加名为FST_DOC_ID_INDEX的唯一索引unique index

innodb全文检索示例

full-text index基于text based columnschar, varchar, text来进行创建用于加速针对text based colums列的dml操作。

一个full-text index可以定义为create table语句的一部分,也可以通过alter tablecreate index语句添加到已经存在的表中。

full-text查询通过match() ... against预发来触发。

innodb full-text design

innodb全文索引基于倒排索引进行设计。倒排索引存储了一系列的words对每个word都存在一个list与之对应list中的元素为包含word的文档

为了支持proximity searchword在list中出现的位置信息也同样被保存。

innodb full-text index tables

当innodb full-text index被创建时一系列index tables都会同时被创建示例如下所示。

创建表并指定fulltext索引

create table fs_text (
    id bigint not null auto_increment,
    content longtext,
    primary key (id),
    fulltext index `idx_fts_fs_text` (content)
);

查询辅助表:

select * from information_schema.innodb_tables where name like 'innodb_demo%'

其中和full-text表相关的索引如下

TABLE_ID NAME FLAG N_COLS SPACE ROW_FORMAT ZIP_PAGE_SIZE SPACE_TYPE INSTANT_COLS TOTAL_ROW_VERSIONS
1822 innodb_demo/fs_text 33 6 96 Dynamic 0 Single 0 0
1823 innodb_demo/fts_000000000000071e_being_deleted 33 4 97 Dynamic 0 Single 0 0
1824 innodb_demo/fts_000000000000071e_being_deleted_cache 33 4 98 Dynamic 0 Single 0 0
1825 innodb_demo/fts_000000000000071e_config 33 5 99 Dynamic 0 Single 0 0
1826 innodb_demo/fts_000000000000071e_deleted 33 4 100 Dynamic 0 Single 0 0
1827 innodb_demo/fts_000000000000071e_deleted_cache 33 4 101 Dynamic 0 Single 0 0
1828 innodb_demo/fts_000000000000071e_00000000000005ad_index_1 33 8 102 Dynamic 0 Single 0 0
1829 innodb_demo/fts_000000000000071e_00000000000005ad_index_2 33 8 103 Dynamic 0 Single 0 0
1830 innodb_demo/fts_000000000000071e_00000000000005ad_index_3 33 8 104 Dynamic 0 Single 0 0
1831 innodb_demo/fts_000000000000071e_00000000000005ad_index_4 33 8 105 Dynamic 0 Single 0 0
1832 innodb_demo/fts_000000000000071e_00000000000005ad_index_5 33 8 106 Dynamic 0 Single 0 0
1833 innodb_demo/fts_000000000000071e_00000000000005ad_index_6 33 8 107 Dynamic 0 Single 0 0

辅助索引表

其中,以innodb_demo/fts_000000000000071e_00000000000005ad_index开头的6张表用于存储倒排索引并被称为辅助索引表

当新增的文档被分割为token时,每个独立的word(也可被称为token被插入到辅助索引表中随着word被插入的还有postionDOC_ID

word按照第一个字符的字符集排序权重被排序,并且在六张辅助索引表中进行分区。

倒排索引被分区在6张辅助索引表中用于支持索引的并行创建。默认情况下2个线程执行tokenize, sort,将word和关联数据插入到index tables操作。

如果想要指定操作上述流程的线程数量,可以对innodb_ft_sort_pll_degree参数进行配置。如果要在大表上创建full-text index可以考虑增加该参数。

table_id hex

辅助索引表命名通过fts_开头,并且后缀index_#。每个辅助索引表都通过辅助索引表表名中16进制的值来和被索引表的table id来进行关联。例如上述示例中16进制值071e代表十进制1822,而表fs_texttable_id刚好为1822

index_id hex

在6张辅助索引表中除了包含table_id的hex外下划线后还存在一个16进制数部分该部分为05ad,代表十进制1453,而索引idx_fts_fs_textindex_id刚好为1453

如果是file per table tablespace那么idnex table将会保存在其自己的tablespace中。