标题图片| CSDN视觉中国下载
本文由“业余程序员”贡献
基本上每个人都会遇到过索引的概念。 即使你没有了解过数据库中的索引,但在生活中你也不可避免地会接触到它。 例如图书目录、词典检索页面、图书馆主题检索等,虽然这些只是一种索引,但发挥的作用却很小。
对于数据库来说,它只是体现了索引的概念,让索引的构建过程更加灵活和自由,从而在不同的场景下优化数据库的查询效率。
索引在实际的数据库应用场景中非常常见,数据库的优化也离不开索引的优化。 同时,指标相关知识也是笔试中出现频率最高的考点之一,是考生理论与实际的最直接体现。
为此,本文将从基础理论出发,从逻辑角度介绍MySQL索引的分类和实现,通过数据结构的实现原理阐明不同结构在构建索引时的优缺点,同时重点讨论化学存储形式索引的组织特征。 分析应用场景。 最后,探讨如何根据不同的应用场景,尽可能构建高性能的索引。 这篇文章的结构如下:
概念
什么是索引?
事实上,该指数并没有一个非常明确的定义,它更多的是一种定性的描述。 简单来说,索引是数据库中以特殊方式存储记录的一种数据结构。 通过索引,可以显着增强数据查询的效率,从而提高服务器的性能。
从技术上讲,索引是一个排序列表,它存储索引的值和包含该值的行的数学地址。 当数据库很大时,索引可以大大提高查询速度。 这是因为使用索引后,不需要扫描全表来定位某一行的数据。 而是先通过索引表找到该行数据对应的数学地址,然后进行访问。 相应的数据。
说到索引,虽然不是MySQL数据库独有的机制,但在关系数据库中也会有类似和不同的实现。 这里我们只讨论MySQL数据库中的索引实现。
其实说是MySQL索引好像不太准确。 因为在MySQL中,索引是在存储引擎层而不是服务器层实现的。 这意味着我们所说的索引正是InnoDB引擎或者MyISAM引擎或者其他存储引擎所实现的。
因此,虽然MySQL中的索引没有统一的标准,但不同的存储引擎实现的索引的工作方法也不同。 并非所有存储引擎都支持相同类型的索引。 即使多个引擎支持相同类型的索引,它们的底层实现也可能不同。
为什么需要索引
说了这么多,索引其实就是给数据库添加了一个“目录页”,这样就可以方便的查询数据了。 这是指数的唯一作用吗? 为什么我们要费这么大的劲去建立和优化索引呢?
言归正传,虽然我从来不喜欢查字典的目录页虚拟主机sql导入软件,不管是英文还是中文。 因为我觉得这样很慢,一一查找索引效率很低。 我习惯使用的方法是直接打开词典,根据打开的位置前后调整。 比如我想找“江fú”这个词,我会随机翻一页。 可能是“F”开头,在“J”前面,所以我会向前转一点; 如果我随机转向“L”,我就会向前转向。 稍微转一下。 重复直到找到。
这大致是类似于二分查找的形式。 看似摆脱了索引的约束,却也能达到比较高的查询效率。 而虽然我又想了想,在计算机的运行处理中,虽然“一一查找索引”的过程很快,但是却无法与我们自动比较部首的效率相提并论。 同时为什么我可以直接打开词典根据字母进行调整呢? 这可能不是因为我脑子里有一个粗略的“索引表”,知道每个字母对应字典中的哪个位置。 其实很模糊,但却是真实的。 (终于强行解释了……)
由此可见,索引的主要用途之一正如其概念中所提到的。 使用索引后,不需要扫描全表来定位某一行的数据。 相反,你首先通过索引表找到该行数据对应的数学地址。 然后访问相应的数据。 这种方式自然减少了服务器响应时需要扫描数据库的数据量。
另外,在数据库中执行范围查询时,如果不使用索引,MySQL会首先扫描数据库中的所有数据行并筛选出目标范围内的行记录,对行记录进行排序并生成临时表。 ,然后通过临时表返回用户查询的目标行记录。 这个过程会涉及临时表的构建和行记录的排序。 当目标行记录较多时,会极大影响范围查询的效率。
因此,在添加索引时,由于索引本身的顺序性,在进行范围查询时,所选行记录已经排序,从而避免了重新排序的问题以及需要构建临时表的问题。
同时,由于索引底层实现的有序性,可以防止在进行数据查询时随机轮询C盘不同磁道。 使用索引后,可以利用对C盘的预读,方便以大致顺序的方式轮询对C盘的数据访问。 这本质上是基于局部性原理来实现的。
局部性原则:当使用一条数据时,一般会立即使用附近的数据。 程序运行时所需的数据一般比较集中。 因为c盘的顺序读取效率很高(不需要寻道时间,只需要很小的旋转时间),所以对于具有局部性的程序,c盘预读可以提高I/O效率。
C盘预读要求每次预读的宽度通常为页的整数倍。 并且数据库系统将节点的大小设置为一页,这样每个节点只需要一次I/O即可满载。 这里的页是通过页式显存管理来实现的。 这里简单提一下这个概念。
分页机制是将显存地址空间划分为若干小的、固定大小的页面。 每页的大小由显存决定。 这样做是为了从虚拟地址映射到化学地址,提高显存和C盘的利用率。
那么,我们来总结一下。 索引的存在有很大的优势,主要体现在以下三点:
以上三点可以大大提高数据库查询的效率,优化服务器性能。 因此,一般来说,为数据库添加高效的索引是优化数据库的重要工作之一。
然而,一切都有两个方面。 索引的存在可以提升性能,但自然也会有其他方面的额外成本。
索引本身以表的形式存储,因此占用额外的存储空间;
索引表的创建和维护需要时间成本,随着数据量的减少而降低;
创建索引会提高数据修改操作(删除、添加、修改)的效率,因为更改数据表时,也需要更改索引表;
因此,对于特别小的表,使用索引的成本会低于直接全表扫描。 在这种情况下,没有必要使用索引。 没办法,成人的世界总是趋利避害的。
逻辑分类
从逻辑上看,索引可以分为单列索引、全文索引、组合索引和空间索引。 其线性列索引可分为字段索引、唯一索引和普通索引。 这里的逻辑可以从SQL语句的角度来理解,也可以从数据库关系表的角度来理解。 下面简单介绍一下这个索引的作用和用法,以及换表时如何添加索引。
字段索引
即主索引,根据字段构建索引,不允许重复,不允许空值;
字段:数据库表中的列或列组合(数组)的值,唯一标识表中的每一行。
加速查询+唯一列值(不能有)+表中只有一个
ALTER TABLE 'table_name' ADD PRIMARY KEY pk_index('col');
唯一索引
用于构建索引的列的值必须是唯一的,并且允许空值。 唯一索引不允许表中的任意两行具有相同的索引值。 例如,在员工表中对员工的姓氏创建唯一索引,这意味着任何两个员工都不能具有相同的姓氏。
加速查询+唯一列值(可用)
ALTER TABLE 'table_name' ADD UNIQUE index_name('col');
普通指数
使用表中的普通列创建的索引没有任何限制。
仅加快查询速度
ALTER TABLE 'table_name' ADD INDEX index_name('col');
全文索引
基于大型文本对象列的索引
ALTER TABLE 'table_name' ADD FULLTEXT INDEX ft_index('col');
综合指数
通过组合多个列创建的索引不允许这些列中的值存在空值。
多个列值组成一个索引,专门用于组合搜索,效率比索引合并低。
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');
在多列组合上建立索引时,会遵循“最左前缀”原则。
最左前缀原则:顾名思义,就是最左优先的意思。 上面的例子中,我们创建了(col1,col2,col3)多列索引,相当于创建了(col1)单列索引、(col1,col2)组合索引和(col1,col2,col3)组合索引。
因此,我们在创建多列索引时,一定要根据业务场景,将最常用的列放在最右边的where谓词中。
空间索引
在空间数据类型的数组上构建的索引可以通过底层的R树来实现。 只是用的比较少,了解一下就可以了。
实现原理
我们知道索引本身底层是通过数据结构来实现的。 根据其底层结构,常见的索引类型可以分为哈希索引、BTree索引、B+Tree索引等,这里我们主要介绍这三种索引背后的实现机制。
哈希索引
顾名思义,哈希索引是通过哈希表实现的。 哈希表的特点在之前的文章《九种数据结构》中已经详细介绍过。 通过哈希表中通配符的对应关系,可以在查询时准确匹配索引的所有列。 哈希索引存储了索引中根据索引列估计出的所有哈希码,并存储了哈希表中指向每个数据行的指针。
上图是通过哈希索引查询行数据的示意图。 可以发现哈希索引也存在哈希冲突,但是通过链地址的方法解决了冲突。 当发送冲突时,需要遍历数组并进行比较,找到最终的结果。
在MySQL中,只有Memory存储引擎显式支持哈希索引,而innodb则隐式支持哈希索引。
这里的隐式支持是指innodb引擎有一个特殊的功能“自适应哈希索引”。 当innodb注意到某些索引值使用特别频繁并且满足哈希特征(比如每个查询的列相同)时,它会基于显存中的B-Tree索引创建哈希索引。 这使得BTree索引也具有哈希索引的一些优点。 这是完全手动的内部行为。
由于哈希结构的特殊性,用于检索效率特别高,通过哈希函数可以一步完成映射。 并且也由于其特殊的结构,哈希索引只适用于某些特定的场合。 哈希索引的局限性[1]:
不支持范围查询,如WHEREa>5; 仅支持等价比较查询,包括=、IN、
不能用于阻止数据的排序操作; 由于哈希函数的映射过程,哈希前后的大小关系丢失虚拟主机sql导入软件,因此无法按照索引值的顺序存储。
不支持部分索引列上的匹配查找,因为哈希索引始终使用索引列的全部内容来估计哈希值。 例如,在数据列(A,B)上建立哈希索引,如果查询只有数据列A,则很难使用该索引。
无法阻止表扫描。 因为当发生哈希冲突时,存储引擎必须遍历数组中的所有行(拉链法)并逐行比较,直到找到所有满足条件的行。
当哈希冲突较多时,索引维护的成本非常高,性能也不一定比BTree索引高。
B树索引
BTree实际上是一个多叉平衡搜索树。 从名字就可以看出,BTree首先是一个多叉搜索树,也就是说它是有序的; 其次,BTree也是平衡的,也就是说它的左右子树的高度差大于等于1。
事实上,BTree需要满足以下条件:
每个叶子节点的高度相同;
每个非叶节点由n-1个键和n个指针组成,其中d