【高频题加分模版训练营】说一说索引?

本问题对应的项目链接:高频题回答模版训练
这种问题属于泛问题,可以说的非常非常多,你完全可以说个几分钟,一顿操作证明一下自己,那应该怎么说呢?

首先我们要有逻辑 + 流畅,一般可以这样:你可以先把可以说的罗列出来,然后拼凑起来strong>,比如索引可以说的有:

1、索引底层结构(B+树)+ 为什么选择了 B+ 树

2、索引类型 + 不同的存储类型不大同

3、通过存储引擎的底层结构会不同(一般强调InnoDB)

4、索引失效的情况

5、选择索引的规则

6、加了索引不一定快

7、优化器什么时候会选择索引什么时候不选择

8、…..
请打卡你的回答,千万不要复制千万不要复制千万不要复制!

共以下 13 个回答

  • 八点上线 永久会员 2024年12月12日 上午1:36

    索引就像书的目录一样,帮助数据库实现快速定位,在innodb引擎中,索引的底层结构是用b+树存储的,非叶子节点不存数据这样一次读取能读取更多的节点,叶子节点存数据并用双向链表连接,方便范围查找,有时索引会失效,例如like后跟“%10”,也有时mysql故意不选择使用索引,这是根据索引的区分度确定的,区分度低导致mysql认为使用索引要扫描的行数比全表扫描要多,也有时mysql选错了,因为这是根据采样分析确定的,有一定误差,这时可以用analyze table重新分析

    0 赞同 0 条回复
  • 終达·斯维达尼亚 永久会员 2024年2月3日 上午3:04

    索引充当如同书页目录一样的功能方便我们查找库中的数据,在InnoDB引擎中Mysql的索引是通过B+树的结构在存储,B+树的叶子结点通过有序的链表相连,在范围查询时可以获得更快的速度,同时只有叶子节点存放Value,其他节点存放的是主键key,因此可以一次加载更多的节点在内存中,减少磁盘加载到内存的次数。Mysql的索引分为主键索引和普通索引,主键索引可以直接通过查询得到数据,而使用普通索引则需要通过一次回表到主键索引上才能得到数据,因此在使用索引时尽量使用主键索引。如果必须使用普通索引的话,可以通过覆盖索引、最左前缀原则、索引下堆等方式减少回表次数,以减少资源消耗。在使用索引查找的时候要注意sql语句的书写,书写操作不当可能不会引发索引查找,比如在sql语句中进行函数操作等。同时系统也会自主判断走索引是否会更快从而决定是否走索引,主要通过索引的区分度来判断,一个索引上不同的值越多,意味着出现相同数值的索引越少,索引区分度也就越大,区分度越大走索引就越有优势,但是系统在判断索引区分度的时候是通过采样的方式遍历部分数据,因此可能会出现判断不准确的情况从而走全表扫描,此时可以在sql语句里加上force关键字让系统强制走索引。

    2 赞同 0 条回复
  • Silence 永久会员 2023年10月21日 上午9:36

    我们平时在看书的时候,通常会有一个目录,我们可以根据这个目录迅速的查找到我们想要查找的内容具体在哪一页。进而就能快速的找到我们想要查看的内容,所以它也是一样的。他就是为了加快查询效率而生的。

    不同的存储引擎,它的底层索引数据结构也是不一样的。这里我们以InnoDB这个存储引擎为例。innodb这个存储引擎,它底层所用索引数据结构是b加速这个数据结构。比加速这个数据结构它有一个非常显著的特点,就是它所有的数据元素都存放在叶子节点上,它的非叶子节点是不存放数据的。这样做有两个好处。第一个好处就是它能够支持范围查询,并且有很大的优势。因为他的所有的数据元素都存放在叶子节点上,并且他的所有的叶子节点都是通过双向链表来进行相互关联的,所以说他就能够非常好的知识范围查询,并且这个范围查询是我们在写SQL语句中经常用到的条件。第二点呢就是说他的非叶子节点都不存放数据,它就能够极大限度的降低这个二叉树的高度。就可以让我们在查询的时候尽量的减少这个磁盘io的次数。进而提高我们的查询效率。

    但是我们加了索引之后并不一定会变得很快。啊,首先有可能说我们在写sql语句的时候进行了一些误操作,就会导致索引失效,比如说我们在写有条件的时候等号的左边。你加入了聚合表达式,或者说是一些算术表达式的话,这时候所以它会失效。嗯,然后还有即便是说你正确的加了索引并且你的sq语句也没有问题的话,你的索引也仍然有可能会失效,这个就跟卖狗它的优化器有关。它的优化器在执行一条SQL语句的时候会判断一下。他走索引更快还是说不走索引更快?如果说他判断出来步骤,所以更快的话,那么他就不会去走索引。

    但是这个索引的优化器它的判断也并不是100%正确的。他主要是根据你所引的这个区分度来进行判断,你到底要不要走所以的通常情况下来说,你的索引区分度越高,你的索引就越有优势,那就越有可能去走,所以反之则不会去走,所以但是他的判断逻辑是经过抽样调查来进行判断的。这样就会导致一个一个问题。他的判断结果完全取决于他的抽样抽样的样本。这个就可能会导致一个比较大的误差性。意思就是说他有可能会选错索引,当我们正确的加了索引,也正确的写了索扣语句之后发现这条查询语句仍然很慢的话,这个时候我们就可以用explain这个命令来让他解释一下他到底具体是如何执行的,它的索引的长度是什么,他选择了什么索引。如果说我们发现他确实走错了索引的话,我们可以加上force这个关键字来让他强制的走某一个索引。并且我们还可以用一些手段让他进行重新的抽样统计一下来让他进行。能得到正确的统计结果。嗯,好,我能说的就是这么多了吧。

    0 赞同 0 条回复
  • 中国用户 永久会员 2023年10月4日 下午8:58

    索引的作用就是定位,相当于目录,加快查找速度
    索引在不同的存储引擎中实现方式并不相同,这里以最常用的InnoDB引擎为例。在InnoDB引擎中索引采用B+树的数据结构实现。
    1.索引的常见模型:
    哈希表这种结构适用于只有等值查询的场景
    有序数组在等值查询和范围查询场景中的性能就都非常优秀。但是,在需要更新数据的时候就麻烦了,你往中间插入一个记录就必须得挪动后面所有的记录,成本太高。
    N 叉树由于在读写上的性能优点,以及适配磁盘的访问模式,已经被广泛应用在数据库引擎中了。
    2.InnoDB 的索引模型:B+ 树
    主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
    非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。
    3.回到主键索引树搜索的过程,我们称为回表。
    覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
    B+ 树这种索引结构,可以利用索引的“最左前缀”,来定位记录。
    MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。

    0 赞同 0 条回复
  • 泡芙 永久会员 2023年6月26日 下午11:22

    一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。一本500页的书,如果你想快速找到其中的某一个知识点,在不借助目录的情况下,那我估计你可得找一会。同样,对于数据库的表而言,索引其实就是它的“目录”。但是索引在不同的存储引擎中实现方式并不相同,这里我就主要讲讲InnoDB引擎相关的吧。

    在InnoDB引擎中索引采用B+树的数据结构来实现。至于为什么选择 B+ 树,这和业务场景有关,如果只选一个数据,那确实是hash更快。但是数据库中经常会选择多条,这时候由于 B+ 树的节点是有序的,而且所有的内容都会存在叶子节点上,并且这个叶子节点是通过双向链表相连的,很好支持范围查找,因此它的查询效率就比 hash 快很多了。

    而且数据库中的索引一般是在磁盘上,数据量大的情况可能无法一次装入内存, B+ 树的非叶子节点只存放 key, 不存放value,这样的设计可以允许数据分批加载,减少磁盘加载到内存的次数,同时树的高度较低,查找速度更快。

    索引类型分为主键索引和非主键索引,基于非主键索引的查询需要多扫描一颗搜索树,也就是回表,因此我们应该尽量使用主键查询。由于 InnoDB 是索引组织表,一般情况下可以创建一个自增主键,这样非主键索引占用的空间最小,当然也有使用业务逻辑字段做主键的应用场景。

    有优点当然也有缺点,由于索引底层的实现方式,一些sql操作会导致索引失效,如进行函数操作、or操作两边索引不一致等,这些情况都是我们应该避免的。

    另外,事无绝对,虽然索引能够加快查询效率,但索引的效率和索引字段的区分度有关,由于优化器通过采样比较效率,可能会出现不走索引而去扫描全表的情况,如果这种情况下索引确实能增加效率,那么可以用force操作强制使用索引。

    0 赞同 0 条回复
  • 。 永久会员 2023年6月17日 下午4:41

    索引是为了加快查询速度,类似于书本的目录,没了索引只能遍历,索引牺牲了一点空间获取了极快的查询速度。索引可以是哈希,通过哈希运算直接得到数据在硬盘的位置,快速把数据复制到内存。索引可以是二叉树搜索树,通过nlogn的时间复杂度和硬盘查询就可以得到目标范围的数据。不同存储引擎使用的索引结构有所不同,比如使用lsm树和哈希的levelDB。
    在MySQL的innodb引擎中使用的索引的数据结构为b+树,它和二叉搜索树一样通过nlogn复杂度得到数据,而且数据都在树的叶子节点,查询复杂度稳定,在插入数据时或者删除数据可能会造成树的分裂或者合并,每次分裂或合并最多影响每一层的两个节点,这些修改操作对硬盘的读写次数相对于avl树的或者红黑树的有明显优势。
    当查询语句中有表达式运算,函数运算,模糊查询,带有or运算,正则表达式或者MySQL的语句优化都可能造成索引失效。
    索引就是为了加快查询速度,应该选择区分度尽可能大的,比如身份证号,名字等,根据需求也可以在分数,价格等加索引。
    加了索引后,可能会因为选择了错误的索引,导致很多非必要的数据被复制到内存,也可能是数据量太大或者太小,不如直接遍历,或者是重复的数据太多,或者需要频繁回表。

    0 赞同 0 条回复
  • mpweixin用户 永久会员 2023年5月26日 下午5:09

    索引可以类比成书的目录,通过直接翻书的形式,来找某个章节的话,可能会很慢,但是如果看了目录再翻,就会快很多。索引在数据库中的应用也是类似这样。
    对于Mysql的索引,它的数据结构采用B+树,使用B+树来存储索引,B+树有以下几个特点,第一,一个结点的子结点可以大于两个,这可以减少树的层数,在磁盘的数据存储里面,层数减少意味着磁盘的寻址次数也会减少,使得查询效率得以提高;第二,数据都存在叶子结点,这个可以使得一个数据页存放更多的结点,减少查询的时候,从磁盘读写到内存的次数;而且叶子节点之间,是用指针相连,形成一个双向链表,这非常适合于数据库中常用的范围查询,知道头或尾,直接就能一整条查出来。
    不同的存储引擎,内部的索引结构会有所不同。例如,常用的InnoDB,主键索引采用的是聚簇索引,而非主键索引采用的是非聚簇索引。所谓聚簇索引,就是行记录和索引都存储在一起;使用InnoDB的表,必须要有一个聚簇索引,如果定义了主键,那么主键索引就是聚簇索引,如果很不幸,这个表没有定义主键,首先选一个唯一的非空列作为聚簇索引;如果连唯一的非空列都没有,那么会选择一个隐藏字段row_id作为表的主键,并且用作这个表的聚簇索引;对于InnoDB的非主键索引,它的叶子结点存的是主键,非叶子结点存的是索引字段的值,所以在条件允许的情况下,我们不应该选择长度太大的列作为索引,这样会使得索引占用的空间太大。
    MyIsam采用的都是非聚簇索引,所以它的行记录、主键索引、非主键索引,是分开三个东西来存储的。

    0 赞同 0 条回复
  • 小雨 永久会员 2023年3月14日 下午3:23

    索引能够在不增加内存的情况下,提高数据库的性能。没有索引的话。查询数据时数据库会进行全盘扫描,速度会慢。有了索引是一个树的数据结构。查询效率会变高,但是修改增加插入删除的效率会受到影响。但是在实际项目运用中查询的情况运用的最多。
    InnoDB引擎将B+树作为索引的底层数据结构,对于普通的二叉排序树来说,如果排列的不合理。他就会变成一个链表。这样我们搜索的时候也相当于全盘扫描。因为我们扫描的次数取决于树的高度。
    AVL树的话是AVL树是一个平衡的二叉树,相对于普通的二叉排序树它能够减少树的高度。
    一般我们将表中的数据和索引存储在磁盘里。但是和内存相比的话,磁盘的IO速度是很慢的。我们查询数据的时候是查询磁盘上的一个磁盘块,就是一个节点一个节点的查,AVL树里只每个节点只存储一个键值对加一个数据,减少时间的方式为尽量每次读取数据要能够多读取。这样的话,磁盘IO的次数就会减少,采用B树的话,一个节点包含多个键值和多个数据这样数的整体高度会进一步减少。
    但是InnoDB中每页的大小是固定的,一个节点上传入的数据量是有限的,对B树再一次优化,那就是用B+数来存储,因为B加数的非叶子节点上是不存储数据的,这样的话,它InnoDB中一页的话就能存储更多的键值,所以说树的整体高度会更矮。IO传输次数会更少。而且B+树中的数据都存储在叶子节点中,并且是按照顺序排列的,并且具有链表结构。如果我们对一个范围内的数据进行查询的话,用B+树因为不需要跨层查找会更加快。

    0 赞同 0 条回复
  • 忆霁昕 永久会员 2023年3月7日 下午11:24

    我们平常在看书的时候,可以通过目录快速找到想看的内容,索引就像是目录,可以加快查询。MySQL 中,不同的存储引擎实现的索引也有所不同,这里以最常用的 InnoDB 存储引擎为例。

    有很多数据结构都可以加快查询,InnoDB 存储引擎使用 B+树实现索引。B+树是有序的,查询起来效率很高,并且所有数据都存储在叶子节点,叶子结点之间通过双向链表连接起来,范围查询也很高效。此外,B+树的非叶子结点只存储 key,不存储 value,这样一个节点可以存储更多的 key,一次读取磁盘可以读取更多 key,减少磁盘 IO 次数。

    并不是加了索引查询就一定会变快,索引存在失效的情况,例如,在查询的时候使用函数操作可能导致索引失效。

    此外,即使加了索引,在查询优化器也可能会不使用索引。优化器会对数据进行抽样,抽样的数据区分度越小,优化器认为使用索引需要扫描的行数越多,有可能会判断使用索引比不使用索引的扫描行数更多,这个时候就会选择全表扫描。

    但是,若抽样的数据误差过大,基于抽样的方法可能会出现误判的情况,这个时候可以使用 analyze 命令让优化器重新统计索引信息,也可以在查询中使用 force index 强制使用索引。

    0 赞同 0 条回复
  • mpweixin用户 永久会员 2023年3月6日 下午10:18

    索引是存储引擎用于快速找到数据记录的一种数据结构,就好比书的目录一样来进行检索便可快速定位记录。数据库没有索引的情况下,数据的查找可能相较于有索引的情况多出很多次磁盘IO操作。我们建立索引的目的就是为了减少磁盘I/O的次数,加快查询速率。
    1)首先索引是基于引擎层来实现的,拿目前流行的MySQL版本来说默认存储引擎为 InnoDB ,而至于InnoDB对索引的实现采用的是B+树,采用B+树的原因有
    ① 减少磁盘IO,B+树这种数据结构,只有叶子节点存放value值,由于MySQL将数据加载到内存默认大小为一页16KB,索引一次能装更多的节点来进行少次IO的高效寻址。
    ② 范围查找 B+树有叶子节点,其叶子节点是有双向链表相连接的,很好地支持范围查找。
    ③ B+树是多路查找树,如果B+树一个节点可以存储1000个键值,那么3层B+树可以存储1000×1000×1000=10亿个数据。一般根节点是常驻内存的,所以一般我们查找10亿数据,只需要2次磁盘IO。
    2)索引的类型在物理存储上可以分为 聚簇索引和非聚簇索引,如InnoDB存储引擎实现的主键索引就为聚簇索引,数据和索引都是存在一个文件中的,也就是数据在这颗索引B+树上。InnoDB相对应的二级索引的叶子节点存储的是记录的主键值。MyISAM存储引擎的主键索引就是非聚簇索引,它的索引文件和数据文件是分开存储的,叶子节点value存储的是记录的地址值。MyISAM的B+树主键索引和辅助索引的叶子节点都是行记录的地址值。
    对于建立了索引,并不意味着任何查询语句都能走索引扫描。写的查询语句是会导致索引失效,常见情况有
    ①对索引使用左或者左右模糊匹配(因为索引 B+ 树是按照「索引值」有序排列存储的,只能根据前缀进行比较,匹配到多个符合条件时不知从哪里开始,于是全表扫描)
    ②对索引使用函数 这指的是等号左边的字段, MySQL8.0有新特性 可以建立函数索引
    ③对索引进行表达式计算 使用库函数
    ④对索引隐式类型转换,如 varchar 字段有数字1 不用引号引起来是不走索引的
    ⑤联合索引的非最左匹配 MySQL8.0有索引跳跃可以解决这一问题。
    ⑥WHERE 子句使用 OR 如在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。
    MySQL 选择索引是查询优化器的工作,走索引的规则优化器对执行的SQL做成本分析。
    主要是判断扫描行数,查看索引的“区分度”,一个索引上不同值的个数叫“基数”,也就是基数越大,区分度越好。MySQL得到索引的基数主要的方法就是采样统计,查询N个数据页的基数,算出平均值,再乘以总页数得到结果。
    除此之外,还要判断执行这条SQL要扫描多少行。不走索引可能也是因为查询的数据要回表操作。这也是优化器的考虑范围之内的。
    还有就是对于复杂SQL 优化器还会结合是否使用临时表、是否排序等因素进行综合判断。
    加了索引不一定快,可能查询优化器判断错误。可以采用 force index 强行选择一个索引。
    我们也可以引导MySQL 使用我们期望的索引。
    在有些场景下,可以新建一个更合适的索引来提供给优化器使用,或者删除掉误用的索引。
    索引固然好用,但也是有缺点存在,建立过多的索引,可能维护起来是很费力的,要避免在有大量重复数据的列上建立索引,因为这个区分度不高。对于经常更新的表也避免创建索引,维护B+树的成本很大。也避免在无序的列作为索引列,插入数据时可能导致页分裂和页合并。不要定义冗余或者重复的索引,如index(a,b,c),就相当于index(a), index(a,b)。

    0 赞同 0 条回复
  • 小肸 永久会员 2023年3月4日 下午11:40

    索引的作用就是定位,加快查找速度。现实生活中有很多用来定位的例子,如书的目录,座位号,楼栋号。与InnoDB存储引擎使用索引的底层数据结构,我认为现实生活中最为接近的例子便是楼栋号。比如每8栋楼排成一列,你只能看到每一列的第一栋楼的号码,现在你要去18号楼,你看到的第一列的楼栋号是1,第二列的楼栋号是9,你就知道18号楼不在第一列,然后看第三列的楼栋号是17,第四列的楼栋号是25,你就知道去第三列找第18号楼,这是顺序查找,可以通过二分查找加快查找速度。假设,17到24又分成两个区,17到20,21到24。同理,你知道去17到20这个区找18号楼,于是你就走入17到20这个区,相当于加载17号到20号上的磁盘页到内存中,如果你找到18号后,又想找到19号,20号,就直接在这个区里顺序找,因为你就在这个区,相当于数据就在内存中。
    索引可以分为两大类,一类为主键索引,也被称为聚簇索引,另一类为二级索引,也可以成为非聚簇索引。可以将聚簇索引当作楼栋,叶子节点存放实际数据,而非聚簇索引可以比作楼盘,叶子节点只存放主键值。但有不准确,因为非聚簇索引是按索引列顺序排列的。我之所以比作楼盘,是便于解释索引下推、覆盖索引、回表的概念。回表就是你在楼盘上看见满意的楼栋,想去详细了解,你就需要去实际楼栋。覆盖索引是你想知道楼栋的外形是怎么样,楼盘已经告诉你了,可以不用去楼栋实际查看。索引下推就是你想知道楼栋号为奇数并且楼栋配有阳台的楼栋,你就直接可以在楼盘上筛选出满足的楼栋,然后去实际楼栋查看,减少回表次数。
    所以mysql的索引就是为了帮助我们更快的查询数据。
    另外,并不是索引越多越好,因为索引需要维护,并且也需要占用空间。应该在where、order by、group by上经常用到的字段上建立索引,经常更新或区分度小的字段、数据量小的表不需要建立索引。.

    1 赞同 0 条回复
  • mpweixin用户 永久会员 2023年2月28日 下午8:45

    索引就像是一个字典的目录,通常我们通过字典查询某个字的时候大概率不会一页页地翻找而是通过前面的目录来快速找到位置再去查看。索引就是这么一个帮助我们快速查找数据的数据结构。
    在mysql中,我们最常用的数据库引擎是innodb,其使用的索引结构是B+树,B+树是一种多叉树,只在非叶子节点上存储索引,叶子节点上存储数据,并且叶子结点以双向链表的形式相连。
    索引的分类可以按照物理的存储分为主键索引和非主键索引,主键索引直接指向数据而非主键索引指向主键的位置。也可以按照字段的特性分为唯一索引、普通索引、主键索引等。
    索引由于其执行逻辑的原因在某些情况下会出现索引失效的情况,就比如对索引使用了函数或表达式的计算、使用了左或左右模糊匹配、在where子句中使用了or但两边不全是索引,这样就会导致索引失效,这是我们应当避免的。还有些情况,mysql在执行时优化器可能会判断使用索引反而更慢所以就不再使用索引,这也是有些时候加了索引但不快的原因,这种情况我们可以使用force index来强制使用索引。
    索引虽然好,但我们不能全部都使用索引,这需要分情况,比如不需要在频繁更新的字段上构建索引,比如用户名单的余额这一字段;不需要在有大量重复数据的字段上建立索引,比如学生名单中的性别等。

    0 赞同 0 条回复
  • Kloro 永久会员 2023年2月26日 下午1:32

    索引就好比是一本字典的目录,要查询一个字如果不走目录的话,需要一页一页翻过去,耗费大量时间;但如果先去查目录的话,就很快速了。因此索引其实就是这样一个目录。
    索引在不同的存储引擎中实现方式并不相同,这里以最常用的InnoDB引擎为例。在InnoDB引擎中索引采用B+树的数据结构实现。与红黑树对比,B+树的高度远远小于红黑树;与HashMap对比,它树的结构能避免出现数据量大时无法一次将装入内存的情况;与B树对比,它的中间节点只存Key不存Value,一个磁盘页能存放更多节点使树变得更矮更胖,且叶子节点存储数据有序、有链表连接使其可以范围查询。
    索引在物理上分为聚簇索引与非聚簇索引。聚簇索引在B+树叶子节点存储的是对应数据本身,非聚簇索引存储的是数据行的位置。聚簇索引在使用时需要二级索引辅助,二级索引叶子节点存储的是主键字段,在通过二级索引查询时会先获取二级索引对应的主键字段,然后回表再通过该主键字段查询对应数据行。聚簇索引适用于范围取数据、排序,可以把相关数据保存在一起,且InnoDB移动数据位置时不需要更新索引信息。但聚簇索引的维护代价很高,特别是索引底层要分页时。
    由于索引底层的实现方式,一些sql操作会导致索引失效,如在sql语句中对索引字段进行函数操作、or操作两边索引不一致时、like通配符破坏索引运行逻辑时、联合索引中where违反最左匹配原则时。
    索引的效率和索引字段的区分度有关,由于优化器通过采样比较效率,可能会出现最后不走索引去全表查询的情况,如果这种情况下索引确实能增加效率,那么可以用force操作强制使用索引。
    在使用索引时可以常用explain看看sql语句的执行情况以便调优。
    由以上信息可以总结,那些经常被”提及”的字段,如经常被where、join、order by且区分度较高的字段适合使用索引。而那些很少被参考、或者类型为text、image等定义上就不适合加索引的字段,或修改性能要求远高于检索性能要求的不适合加索引。

    1 赞同 1 条回复

# 回答此问题

后才能回答