首先,索引的概念很明确,它是一种排好序的、能提升查询性能的数据结构,核心作用就是加快查询速度。
从分类来看,主要分聚簇索引和非聚簇索引。聚簇索引也就是主键索引,它的索引和行数据是存在同一个叶子节点上的;非聚簇索引就是非主键索引,索引对应的存储数据是主键值。
再说说索引的底层结构,用的是 B + 树。那为什么不用 hash 呢?因为 hash 只支持等值查询,不支持范围查询,实际业务里范围查询很常用,所以不合适。
先对比下 B 树和 B + 树。B 树的非叶子节点和叶子节点都存索引值和行数据,假设索引 8B、行数据 1K,加起来 1032B,而 MySQL 一页是 16K,这样一页大概能存 15 条数据。那存储大量数据时,树的高度会越来越高,查询路径变长,效率就低了。
而 B + 树不一样,非叶子节点只存索引值和指向下个索引值的指针,索引 8B 加指针 6B 共 14B,一页能存 1170 个。叶子节点才存索引值和行数据,还会冗余非叶子节点的索引值,而且节点间是双向链表,区间访问效率高。这样一来,B + 树能用较低的深度存大量数据,树越浅查询次数越少,性能就越好,还支持范围查询。
再看主键索引,InnoDB 表必须有主键,不手动创建的话,数据库会自动建。一般用无业务意义的自增主键,因为插入数据始终放最后,能快速找到位置,不用移动数据、旋转树,减少额外开销。它的非叶子节点存主键值,叶子节点存行数据,通过主键查询能直接找到数据,速度很快。
非主键索引里,普通索引是在普通字段上建的,非叶子节点存索引列值,叶子节点存主键值。因为如果存储数据,数据变了不仅要维护主键索引,还要改其他索引,开销太大。
唯一索引是给唯一列创建的,用 unique 标识。联合索引是给多个非主键列建的,比如表有 id、name、age、phone,索引可以建在 name、age、phone 上。全文索引因为 Elasticsearch 的存在,用得相对少些。
创建索引也有要求:单表索引不超过 5 个,联合索引的字段也不超过 5 个;经常增删改的字段、枚举值字段不适合建索引;不常改、常查询的字段适合建;大长度字段可以设前缀索引,比如给 users 表的 username 前 10 个字符建索引,语法是 “CREATE INDEX idx_username_prefix ON users (username (10));”。
最后说下创建语法。主键索引命名是 pk列名;普通索引是 “create index 索引名称 on 表名 (列名)”,命名 idx列名;唯一索引是 “create unique index 索引名称 on 表名 (列名)”,命名 uk列名;联合索引是 “create index 索引名称 on 表名 (列 1, 列 2)”,命名 idx列 1_列 2。