我们在看书的时候,都知道有目录,我们可以通过目录快速的找到书中的内容,而书中的目录就是充当书的索引。在数据库中的索引也是一样的。
索引的定义:
索引是帮助存储引擎快速获取数据的一种数据结构,即数据目录
索引的优点:
索引最大的优点就是提高查询速度
索引的缺点:
1. 要占据物理空间
2. 创建和维护索引都需要耗时,数据量越大越耗时
3. 会降低表的增删改效率,因为每次增删改都会动态维护索引
所以索引的使用也要根据具体情况而定,一般只会在这些这段下建立索引:有唯一性限制的字段,经常在where语句出现的字段,经常在GROUP BY 和 ORDER BY 出现的字段。
而不建议建立索引的字段:
1. 不经常在where语句,GROUP BY 和 ORDER BY 语句的字段,不建索引
2. 大量重复数据的字段,不建索引
3. 表数据太少,不建索引
4. 经常更新的字段,不建索引
在MYSQL中,从数据结构进行索引分类:
B+tree索引:把所有的数据都存储在叶子结点上面,非叶子结点只存储索引,这样可以保证最少次数的IO提高索引查询的性能
Hash索引:就是根据给定的字段,进行创建Hash值。可以很快的进行单个匹配度查询,但是无法做到范围查询
Full-text索引:一个比较特殊的索引,一般用的也很少。它查找的是文本中的关键词,而不是比较索引中的值。全文索引更类似于搜索引擎做的事
但是每种存储引擎所支持的索引是不相同的,下面我们对MYSQL中的 常见存储引擎 Innodb和MyISAM进行对比:
从对比中我们知道每一种存储引擎支持的索引类型不一定相同。而下面我们重点讲的是Innodb存储引擎中B+Tree 索引类型,也是MYSQL5.5之后的默认存储引擎。
在创建表的时候,Innodb存储引擎会根据具体场景设计索引:
1. 有主键,那么主键做聚簇索引的key
2. 没有主键,就选择第一个不包含 NULL 值的唯一列作为聚簇索引的key
3. 以上都不符合,那就主动生成一个隐式自增 id 列作为聚簇索引的key
除了聚簇索引,其他索引都属于辅助索引,也被称为二级索引或非聚簇索引。创建的主键索引和二级索引默认使用的是 B+Tree 索引。
那么 B+Tree 索引在存储是什么样子的呢?
B+Tree 是一种多叉树,叶子点才存放数据,非叶子点只存放索引,而且每个节点里的数据是按主键顺序存放的。每一层父节点的索引值都会出现在下层子节点的索引值中,因此在叶子节点中,包括了所有的索引值信息,并且每一个叶子节点都指向下一个叶子节点,形成一个链表。如下图:
主键索引 B+ Tree假如我们要查找主键值为30的数据,查找过程如下:
1. 将 30 与根节点的索引数据 (15,56,77) 比较,30 在 15 和 56 之间,所以根据 B+Tree的搜索逻辑,找到第二层的索引数据 (15,20,49);
2. 在第二层的索引数据 (15,20,49)中进行查找,因为 30 在 20 和 49 之间,所以找到第三层的索引数据(20, 30);
3. 在叶子节点的索引数据(20, 30)中进行查找,然后我们找到了主键值为 30 的行数据。
从例子中我们知道,我们总共走了3个节点找到数据,其实也就是说我们进行了3次I/O操作。因为所有数据(索引和数据)都是存在磁盘里的,我们没读取一个节点就会就行一次I/O操作。
而且B+Tree存储千万级别的数据也就3-4层就可以满足,也就是说查询千万级别的数据也就进行了3,4次I/O操作。所以B+Tree 相比于 B 树和二叉树来说,最大的优势在于查询效率很高,因为即使在数据量很大的情况,查询一个数据的磁盘 I/O 依然维持在 3-4次。
如果是二级索引(非聚簇索引),那是不是跟主键索引(聚簇索引)一样呢?
肯定是不一样的。它们的区别如下:
1. 聚簇索引的 B+Tree 的叶子节点存放的是实际的数据记录,而且实际的数据记录只会存在这里。
2. 非聚簇索引的 B+Tree 的叶子节点存放是主键值和索引值,没有实际数据记录。
所以说,如果要通过非聚簇索引找到一条完整的实际数据记录,那么它得也通过非聚簇索引找到叶子节点,然后获取主键值,再根据这个主键值在主键索引的B+Tree中找到对应的叶子节点,拿到完整的实际数据记录。而这个过程就是做回表,也就是进行了两次B+Tree搜索找到数据。如果我们通过非聚簇索引一次搜索就得到想要的数据结果,那么久叫做覆盖索引。下面说明非聚簇索引的过程,如下:
二级索引 B+Tree 回表上面有两个问题:
B+Tree的3-4层高能存储千万级别的数据,怎么计算的?
详细了解的这个问题可以看这篇:
为什么 MySQL InnoDB 选择 B+tree 作为索引的数据结构?
详细了解的这个问题可以看这篇:
在MYSQL中,从物理存储进行索引分类:
主键索引(聚簇索引)
二级索引(非聚簇索引/辅助索引)
这两个区别在上面有说过,区别在于叶子节点存储的数据。
在MYSQL中,从字段特性进行索引分类:
主键索引
唯一索引
普通索引
前缀索引
主键索引就是建立在主键上的索引,通常在创建表格的时候一起创建,一张表只能有一个主键,而且不能为空。
创建方法:
CREATE TABLE table_name (
....
PRIMARY KEY (index_column_1)
);
唯一索引就是建立在 UNIQUE 字段上的索引,一张表可以有多个唯一索引,但索引列的值必须唯一,但是允许有空值。
创建方法:
方法一:
CREATE TABLE table_name (
....
UNIQUE KEY(index_column_1,index_column_2,...)
);方法二:
CREATE UNIQUE INDEX index_name ON table_name(index_column_1,index_column_2,...);
普通索引就是建立在 普通字段上的索引。
创建方法:
方法一:
CREATE TABLE table_name (
....
INDEX(index_column_1,index_column_2,...)
);方法二:
CREATE INDEX index_name ON table_name(index_column_1,index_column_2,...);
前缀索引是指对字符类型字段的前几个字符建立的索引,而不是在整个字段上建立的索引,前缀索引可以建立在字段类型为 char、 varchar、binary、varbinary 的列上。使用前缀索引的目的是为了减少索引占用的存储空间,提升查询效率.
创建方法:
方法一:
CREATE TABLE table_name (
column_list,
INDEX(column_name(length))
);方法二:
CREATE INDEX index_name ON table_name(column_name(length));
在MYSQL中,从字段个数进行索引分类:
单列索引
联合索引(复合索引)
建立在单列上的索引称为单列索引, 比如主键索引
联合索引就是将多个字段组合成一个索引。联合索引的遵循的规则:
最左匹配原则,即按照最左优先的方式进行索引的匹配。所以建立联合索引时的字段顺序,对索引效率也有很大影响。越靠前的字段被用于索引过滤的概率越高,实际开发工作中建立联合索引时,要把区分度大的字段排在前面,这样区分度大的字段越有可能被更多的 SQL 使用到。区分度就是某个字段 column 不同值的个数「除以」表的总行数,即区分度 = distinct(columnn)/ count(*)
例如,我们有个(a,b,c)联合索引,符合联合索引的:
where a = 2;
where a = 2, b = 2;
where a = 2, b = 2, c = 2;
不符合联合索引的:
where b = 2;
where c = 2;
where b = 2, c = 2;
不符合联合索引是因为不符合最左匹配原则。
创建索引请查看上面具体索引部分
查看索引:
SHOW INDEX FROM table_name;
删除索引:
DROP INDEX index_name ON table_name;
或
ALTER TABLE table_name DROP INDEX index_name;
MySQL数据库优化总结中的 索引优化