MySQL中的索引
索引的作用: 索引就是帮助mysql高速的获取数据的一种数据结构,索引就像是一种书的目录一样
索引的类型
Hash: 查询时调用Hash函数获得地址,回表查询实际数据。(InnoDB和MylSAM不支持,Memory支持)。
B+树: 每次从根节点出发去查询,然后得到地址,回表查询实际数据。
二叉查找树、B树、B+树
二叉查找树(二叉排序树、二叉搜索树): 一个节点最多两个子节点(左小右大),查询次数和比较次数都是最小的,但是索引是存在磁盘的,当数据量过大的时候,不能直接把整个索引文件加载到内存,需要分多次IO,最坏的情况IO的次数就是树的高度,为了减少IO,需要把树从竖向变成横向。
B树( B- ): 是一种多路查询树,每个节点包含K个子节点,节点都存储索引值和数据,K是B树的阶(树高被称为树的阶)。虽然比较的次数比较多,但是是在内存的比较,可以忽略不计,但是B树IO的次数要比二叉查找树要少,因为B树的高度可以更低。
B+树: B树的升级版,只有叶子节点储存的是索引值指向的数据库的数据。
为什么使用B+树不用B树
-
B树只适合随机检索,而B+树同时支持随机检索和顺序检索(因为叶子节点相当于链表,保存索引值都是有序的)。
顺序检索: 按照序列顺序遍历比较找到给定值。
随机检索: 不断从序列中随机抽取数据进行比较,最终找到结果。 -
减少了磁盘IO,提高空间利用率: 因为B+树非叶子节点不会存放数据,只有索引值,所以非叶子节点可以保存更多的索引值,这样B+树就可以更矮,减少IO次数。
-
B+树适合范围查找: 这才是关键,因为数据库大部分都是范围查找,B+树的叶子节点是有序链表,直接遍历就行,而B树的范围查找可能两个节点距离很远,只能通过中序遍历去查找,所以使用B+树更合适。
中序遍历: (根在中,从左往右,一棵树的左子树永远在根前面,根永远在右子树前面)
怎么避免索引失效
- 某列使用范围查询(>、<、like、between and)时, 右边的所有列索引也会失效。
- 不要对索引字段进行运算。
- 在where子句中不要使用 OR、!=、<>和对值null的判断。
- 避免使用’%'开头的like的模糊查询。
- 字符串不加单引号,造成索引失效。
索引怎么设计
-
选择唯一性索引:值是唯一的,查询的更快。
-
经常作为查询条件的字段加索引。
-
为经常需要排序、分组和联合操作的字段建立索引:order by、group by、union(联合)、distinct(去重)等。
-
限制索引个数:索引数量多,需要的磁盘空间就越多,更新表时,对索引的重构和更新就很费劲。
-
表数据少的不建议使用索引(百万级以内):数据过少,有可能查询的速度,比遍历索引的速度都快。
-
删除不常用和不再使用的索引。
-
用类型小的类型做索引:比如:int和BIGINT能用int就使用int。因为类型小,查询速度快和索引占用的空间更少。
-
使用前缀索引,要是字符串越长,那么索引占的空间越大,并且比较起来就时间就越长。
使用索引的优点和缺点
优点:
-
索引能够显著加速数据检索过程。通过直接定位到数据所在的位置,避免了全表扫描,尤其是在大型数据表中,查询性能提升尤为明显。
-
对于包含
ORDER BY
和GROUP BY
子句的查询,如果排序或分组的列上有索引,数据库可以利用索引的预排序特性,减少甚至避免额外的排序操作,从而加快查询速度。 -
唯一索引可以确保表中不会有重复的记录,这对于维护数据完整性非常重要,比如身份证号、邮箱地址等唯一标识字段。
-
由于索引是对数据的排序引用,数据库在查找数据时可以更快地定位到具体磁盘块,减少了磁盘I/O操作次数,提升了整体效率。
-
外键索引可以加强表间的参照完整性,确保在插入、更新或删除操作时,相关联的数据保持一致。
缺点:
- 索引也是一个文件,所以会占用空间。
- 降低更新的速度,因为不光要更新数据,还要更新索引。
索引的类型
1. 普通索引(Non-Unique Index)
普通索引是最基本的索引类型,没有任何唯一性约束。
创建SQL示例:
-- 在已存在的表上创建索引
CREATE INDEX idx_employee_name ON employees(name);
-- 在创建表的同时定义索引
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
-- 这里定义了一个名为idx_employee_name的索引
INDEX idx_employee_name (name)
);
注解: 这种索引可以加快基于name
列的查询速度,但允许索引列中存在重复值。
2. 唯一索引(Unique Index)
唯一索引要求索引列的值必须唯一,但允许有多个NULL值(除非列定义为NOT NULL)。
创建SQL示例:
CREATE UNIQUE INDEX idx_employee_email ON employees(email);
注解: 确保email
列中的值是唯一的,有助于快速定位记录,同时保持数据的唯一性约束。
3. 主键索引(Primary Key Index)
主键索引是特殊的唯一索引,不允许NULL值,并且每个表只能有一个主键。
创建SQL示例:
-- 在创建表时定义主键
CREATE TABLE employees (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255) UNIQUE
);
-- 或者在表创建后添加主键(不常见,因为通常主键在创建表时定义)
ALTER TABLE employees ADD PRIMARY KEY (id);
注解: 主键自动成为聚集索引,决定了表中数据的物理排列顺序。
4. 联合索引(Composite Index / Multi-Column Index)
联合索引是在多个列上创建的索引,优化涉及多个列的查询。
创建SQL示例:
CREATE INDEX idx_employee_name_email ON employees(name, email);
注解: 该索引对name
和email
两列联合排序,查询时如果条件中包含了这两个列或它们的前缀,索引将最有效。
5. 全文索引(Full-Text Index)
全文索引适用于文本类型列的全文搜索。
创建SQL示例:
CREATE FULLTEXT INDEX idx_employee_bio ON employees(bio);
注解: 适用于bio
列的大文本内容搜索,提高了复杂的文本搜索性能。
6. 空间索引(Spatial Index)
空间索引用于优化地理空间数据类型的查询,如点、线、面等。
创建SQL示例:
CREATE SPATIAL INDEX idx_employee_location ON employees(location);
注解: 当location
列存储地理坐标或形状时,空间索引可以加速地理位置相关的查询。
7. 覆盖索引(Covering Index)
虽然不是独立的索引类型,但它是索引设计的一个概念,指的是索引包含了查询所需的所有列,使得MySQL可以直接从索引中获取数据而无需回表查询。
创建SQL示例:
-- 例如,如果经常执行以下查询,可以创建一个覆盖索引
SELECT name, email FROM employees WHERE age > 30;
-- 创建一个包含(name, email, age)的索引,使其成为覆盖索引
CREATE INDEX idx_employee_age_name_email ON employees(age, name, email);
注解: 通过包含查询中需要的所有列,覆盖索引可以显著提高查询性能,减少磁盘I/O。
请注意,选择合适的索引类型和设计时,需根据实际的数据分布、查询模式和性能需求来决定,以达到最佳的性能优化效果。