问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

如何理解并正确使用MySql索引

发布网友 发布时间:2022-04-21 05:40

我来回答

3个回答

懂视网 时间:2022-04-07 18:45

一、什么是索引?

??在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。

??当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量数据库系统时间,并造成大量磁盘I/O操作;第二种就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。

??MySQL5.5以后InnoDB储引擎使用的索引数据结构主要用:B+Tree;本篇文章带大家以B+Tree前世今生为主线来聊一聊;

**Mark**

B+Tree可以对<,<=,=,>,>=,BETWEEN,IN,以及不以通配符开始的LIKE使用索引。(MySQL5.5后)

??这些事实或许会颠覆你的一些认知,比如在你读过的其他文章或书中。以上这些都属于“范围查询”,都是不走索引的!

??没错,早先5.5以前优化器是不会选择通过索引搜索的,优化器认为这样取出的行多与全表扫描的行,因为还要回表查一次嘛,可能会涉及I/O的行数更多,被优化器放弃。

??经过算法(B+Tree)优化后,支持对部分范围类型的扫描(得利与B+Tree数据结构的有序性)。该做法同时也违反了最左前缀原则,导致范围查询后的条件无法用到联合索引,我们在后面详细说明。

二、索引的优缺点

1、优点

  1. 索引大大减小了服务器需要扫描的数据量
  2. 索引可以帮助服务器避免排序和临时表
  3. 索引可以将随机I/O变成顺序I/O

2、缺点

  1. 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存索引文件。
  2. 建立索引会占用磁盘空间的索引文件。一般情况这个问题不算严重,但如果你在一个大表上创建了多种组合索引,且伴随大量数据量插入,索引文件大小也会快速膨胀。
  3. 如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
  4. 对于非常小的表,大部分情况下简单的全表扫描更高效;

??因此应该只为最经常查询和最经常排序的数据列建立索引。(MySQL里同一个数据表里的索引总数限制为16个)

??数据库存在的意义之一就是是解决数据存储和快速查找的。那么数据库的数据存在哪?没错,是磁盘,磁盘的优点是啥?便宜!缺点呢?相比内存访问速度慢。

??那么你知道MySQL索引主要使用的数据结构么?

??B+树!你脱口而出。

??那 B+树 是什么样的数据结构?MySQL索引又是为什么选择了B+树呢?

??其实最终选用 B+树 是经历了漫长的演化:

二叉排序树 → 二叉平衡树 → B-Tree(B树) → B+Tree(B+树)

??有小伙伴问我“B树 跟 B-树有什么区别”?这里普及一下,MySQL数据结构只有B-Tree(B树)和B+Tree(B+树),多只是读法不同罢了,“B-Tree” 一般统称为B树,你叫他B-树也行~~

??还有小伙伴提到的红黑树,是编程语言中的存储结构,不是MySQL的;如Java的HashMap就是用的链表加红黑树。

??好了,今天就带着大家一起看一下演化成 B+树 的过程吧。

三、B+Tree索引的前世今生

1、二叉排序树

??理解B+树之前,简单说一下二叉排序树,对于一个节点,它的左子树的孩子节点值都要小于它本身,它的右子树的孩子节点值都要大于它本身,如果所有节点都满足这个条件,那么它就是二叉排序树。(此处可以串一下二分查找的知识点)
在这里插入图片描述

上图是一颗二叉排序树,你可以尝试利用它的特点,体验查找9的过程:

  • 9比10小,去它的左子树(节点3)查找
  • 9比3大,去节点3的右子树(节点4)查找
  • 9比4大,去节点4的右子树(节点9)查找
  • 节点9与9相等,查找成功
  • 一共比较了4次,那你有没有想过上述结构的优化方式?

    2、AVL树 (自平衡二叉查找树)

    在这里插入图片描述

    上图是AVL树,节点个数和值均和二叉排序树一摸一样

    再来看一下查找9的过程:

  • 9比4大,去它的右子树查找
  • 9比10小,去它的左子树查找
  • 节点9与9相等,查找成功
  • ??一共比较了3次,同样的数据量比二叉排序树少了一次,为什么呢?因为AVL树高度要比二叉排序树小,高度越高意味着比较的次数越多;不要小看优化的这一次,假如是200w条数据,比较次数会明显地不同。

    ??你可以想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间,这个查询可真够慢的!

    3、B树(Balanced Tree)多路平衡查找树 多叉的

    B树是一种多路自平衡搜索树,它类似普通的二叉树,但是B书允许每个节点有更多的子节点。B树示意图如下:

    在这里插入图片描述

    B树的特点:

    1. 所有键值分布在整个树中
    2. 任何关键字出现且只出现在一个节点中
    3. 搜索有可能在非叶子节点结束
    4. 在关键字全集内做一次查找,性能逼近二分查找算法

    ??为了提升效率,要尽量减少磁盘I/O的次数。实际过程中,磁盘并不是每次严格按需读取,而是每次都会预读。

    ??磁盘读取完需要的数据后,会按顺序再多读一部分数据到内存中,这样做的理论依据是计算机科学中注明的局部性原理:

  • 由于磁盘顺序读取的效率很高(不需要寻址时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率.预读的长度一般为页(page)的整倍数。
  • MySQL(默认使用InnoDB引擎),将记录按照页的方式进行管理,每页大小默认为16K(可以修改)。
  • B-Tree借助计算机磁盘预读机制:

    ??每次新建节点的时候,都是申请一个页的空间,所以每查找一个节点只需要一次I/O;因为实际应用当中,节点深度会很少,所以查找效率很高.

    ??那么最终版的 B+树 是如何做的呢?

    4、B+ Tree (B+树是B树的变体,也是一种多路搜索树)

    在这里插入图片描述

    从图中也可以看到,B+树与B树的不同在于:

    1. 所有关键字存储在叶子节点,非叶子节点不存储真正的data,从而可以快速定位到叶子结点。
    2. 为所有叶子节点增加了一个链指针,意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同,很适合查找范围数据。

    **因此,B+Tree可以对<,<=,=,>,>=,BETWEEN,IN,以及不以通配符开始的LIKE使用索引。**

    B+树的优点:

    比较的次数均衡,减少了I/O次数,提高了查找速度,查找也更稳定。

  • B+树的磁盘读写代价更低
  • B+树的查询效率更加稳定
  • ??要知道的是,你每次创建表,系统会为你自动创建一个基于ID的聚集索引(上述B+树),存储全部数据;你每次增加索引,数据库就会为你创建一个附加索引(上述B+树),索引选取的字段个数就是每个节点存储数据索引的个数,注意该索引并不存储全部数据。

    四、为什么MySQL索引选择了 B+树 而不是 B树?

    1. B+树更适合外部存储(一般指磁盘存储),由于内节点(非叶子节点)不存储data,所以一个节点可以存储更多的内节点,每个节点能索引的范围更大更精确。也就是说使用B+树单次磁盘I/O的信息量相比较B树更大,I/O效率更高。
    2. mysql是关系型数据库,经常会按照区间来访问某个索引列,B+树的叶子节点间按顺序建立了链指针,加强了区间访问性,所以B+树对索引列上的区间范围查询很友好。而B树每个节点的key和data在一起,无法进行区间查找。

    五、程序员,你应该知道的索引知识点

    1、回表查询

    比如你创建了name, age索引 name_age_index,查询数据时使用了

    select * from table where name ='陈哈哈' and age = 26;
    1复制代码

    ??由于附加索引中只有name 和 age,因此命中索引后,数据库还必须回去聚集索引中查找其他数据,这就是回表,这也是你背的那条:少用select * 的原因。

    2、索引覆盖

    结合回表会更好理解,比如上述name_age_index索引,有查询

    select name, age from table where name ='陈哈哈' and age = 26;
    1复制代码

    ??此时select的字段name,age在索引name_age_index中都能获取到,所以不需要回表,满足索引覆盖,直接返回索引中的数据,效率高。是DBA同学优化时的首选优化方式。

    3、最左前缀原则

    ??B+树的节点存储索引顺序是从左向右存储,在匹配的时候自然也要满足从左向右匹配;通常我们在建立联合索引的时候,也就是对多个字段建立索引,相信建立过索引的同学们会发现,无论是Oracle还是 MySQL 都会让我们选择索引的顺序,比如我们想在a,b,c三个字段上建立一个联合索引,我们可以选择自己想要的优先级,a、b、c,或者是b、a、c 或者是c、a、b等顺序。 为什么数据库会让我们选择字段的顺序呢?不都是三个字段的联合索引么?这里就引出了数据库索引的最左前缀原理。

    ??在我们开发中经常会遇到明明这个字段建了联合索引,但是SQL查询该字段时却不会使用索引的问题。比如索引abc_index:(a,b,c)是a,b,c三个字段的联合索引,下列sql执行时都无法命中索引abc_index的;

    select * from table where c = '1';
    
    select * from table where b ='1' and c ='2';
    123复制代码

    以下三种情况却会走索引:

    select * from table where a = '1';
    
    select * from table where a = '1' and b = '2';
    
    select * from table where a = '1' and b = '2' and c='3';
    12345复制代码

    从上面两个例子大家是否阔以看出点眉目?

    ??是的,索引abc_index:(a,b,c),只会在(a)、(a,b)、(a,b,c) 三种类型的查询中使用。其实这里说的有一点歧义,其实(a,c)也会走,但是只走a字段索引,不会走c字段。

    ??另外还有一个特殊情况说明下,下面这种类型的也只会有 a与b 走索引,c不会走。

    select * from table where a = '1' and b > '2' and c='3';
    1复制代码

    ??像上面这种类型的sql语句,在a、b走完索引后,c已经是无序了,所以c就没法走索引,优化器会认为还不如全表扫描c字段来的快。

    **最左前缀:顾名思义,就是最左优先,上例中我们创建了a_b_c多列索引,相当于创建了(a)单列索引,(a,b)组合索引以及(a,b,c)组合索引。**

    ??因此,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。

    4、索引下推优化

    还是索引name_age_index,有如下sql

    select * from table where name like '陈%' and age > 26;
    1复制代码

    该语句有两种执行可能:

  • 命中name_age_index联合索引,查询所有满足name以"陈"开头的数据, 然后回表查询所有满足的行。
  • 命中name_age_index联合索引,查询所有满足name以"陈"开头的数据,然后顺便筛出age>20的索引,再回表查询全行数据。
  • 显然第2种方式回表查询的行数较少,I/O次数也会减少,这就是索引下推。所以不是所有like都不会命中索引。

    六、使用索引时的注意事项

    1、索引不会包含有null值的列

    ??只要列中包含有null值都将不会被包含在索引中,复合索引中只要有一列含有null值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时建议不要让字段的默认值为null。

    2、使用短索引

    ??对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个char(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

    3、索引列排序

    ??查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

    4、like语句操作

    ??一般情况下不推荐使用like操作,如果非使用不可,如何使用也是一个问题。like “%陈%” 不会使用索引而like “陈%”可以使用索引。

    5、不要在列上进行运算

    这将导致索引失效而进行全表扫描,例如

    SELECT * FROM table_name WHERE YEAR(column_name)<2017;
    1复制代码

    6、不使用not in和<>操作

    这不属于支持的范围查询条件,不会使用索引。

    我的体会

    ??曾经,我一度以为我很懂MySQL。

    ??刚入职那年,我还是个孩子,记得第一个需求是做个统计接口,查询近两小时每隔5分钟为一时间段的网站访问量,JSONArray中一共返回24个值,当时菜啊,写了个接口循环二十四遍,发送24条SQL去查(捂脸),由于那个接口,被技术经理嘲讽~~表示他写的SQL比我吃的米都多。虽然我们山东人基本不吃米饭,但我还是羞愧不已。。
    然后经理通过调用一个dateTime函数分组查询处理一下,就ok了,效率是我的几十倍吧。从那时起,我就定下目标,深入MySQL学习,万一日后有机会嘲讽回去?

    ??筒子们,MySQL路漫漫,其修远兮。永远不要眼高手低,一起加油,希望本文能对你有所帮助。

    热心网友 时间:2022-04-07 15:53

    MySQL索引类型包括:
    (1)普通索引
    这是最基本的索引,它没有任何*。它有以下几种创建方式:
    ◆创建索引
    CREATE INDEX indexName ON mytable(username(length)); 如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length,下同。
    ◆修改表结构
    ALTER mytable ADD INDEX [indexName] ON (username(length))
    ◆创建表的时候直接指定
    CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) ); 删除索引的语法:
    DROP INDEX [indexName] ON mytable;
    (2)唯一索引
    与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:
    ◆创建索引
    CREATE UNIQUE INDEX indexName ON mytable(username(length))
    ◆修改表结构
    ALTER mytable ADD UNIQUE [indexName] ON (username(length))
    ◆创建表的时候直接指定
    CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );
    (3)主键索引
    它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引:
    CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) ); 当然也可以用 ALTER 命令。记住:一个表只能有一个主键。
    (4)组合索引
    为了形象地对比单列索引和组合索引,为表添加多个字段:
    CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL ); 为了进一步榨取MySQL的效率,就要考虑建立组合索引。就是将 name, city, age建到一个索引里:
    ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age); 建表时,usernname长度为 16,这里用 10。这是因为一般情况下名字的长度不会超过10,这样会加速索引查询速度,还会减少索引文件的大小,提高INSERT的更新速度。
    如果分别在 usernname,city,age上建立单列索引,让该表有3个单列索引,查询时和上述的组合索引效率也会大不一样,远远低于我们的组合索引。虽然此时有了三个索引,但MySQL只能用到其中的那个它认为似乎是最有效率的单列索引。

    热心网友 时间:2022-04-07 17:11

    在满足语句需求的情况下,尽量少的访问资源是数据库设计的重要原则,这和执行的 SQL 有直接的关系,索引问题又是 SQL 问题中出现频率最高的,常见的索引问题包括:无索引(失效)、隐式转换。
    1. SQL 执行流程看一个问题,在下面这个表 T 中,如果我要执行 select * from T where k between 3 and 5; 需要执行几次树的搜索操作,会扫描多少行?mysql> create table T (    -> ID int primary key,    -> k int NOT NULL DEFAULT 0,    -> s varchar(16) NOT NULL DEFAULT '',    -> index k(k))    -> engine=InnoDB;mysql> insert into T values(100,1, 'aa'),(200,2,'bb'),\      (300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
    这分别是 ID 字段索引树、k 字段索引树。 

    这条 SQL 语句的执行流程:

    1. 在 k 索引树上找到 k=3,获得 ID=3002. 回表到 ID 索引树查找 ID=300 的记录,对应 R33. 在 k 索引树找到下一个值 k=5,ID=5004. 再回到 ID 索引树找到对应 ID=500 的 R4

    5. 在 k 索引树去下一个值 k=6,不符合条件,循环结束

    这个过程读取了 k 索引树的三条记录,回表了两次。因为查询结果所需要的数据只在主键索引上有,所以必须得回表。所以,我们该如何通过优化索引,来避免回表呢?
    2. 常见索引优化2.1 覆盖索引覆盖索引,换言之就是索引要覆盖我们的查询请求,无需回表。

    如果执行的语句是 select ID from T wherek between 3 and 5;,这样的话因为 ID 的值在 k 索引树上,就不需要回表了。

    覆盖索引可以减少树的搜索次数,显著提升查询性能,是常用的性能优化手段。

    但是,维护索引是有代价的,所以在建立冗余索引来支持覆盖索引时要权衡利弊。

    2.2 最左前缀原则

    B+ 树的数据项是复合的数据结构,比如 (name,sex,age) 的时候,B+ 树是按照从左到右的顺序来建立搜索树的,当 (张三,F,26) 这样的数据来检索的时候,B+ 树会优先比较 name 来确定下一步的检索方向,如果 name 相同再依次比较 sex 和 age,最后得到检索的数据。

    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    什么时候功率最大 最小 家电多少功率算高功率 大功率用电器在开启瞬间,需要比正常使用功率大很多的启动电流,这是为什 ... 大功率电器设备为什么不能一下开到最大 有一个节能灯突然坏了,是哪个件坏了? 我不知道是节能灯坏了,还是开关面板坏了,按下开关面板时,节能灯有时... 为什么节能灯老是烧坏 湖州南太湖新区包括龙之梦吗 南太湖新区有哪些地方 南太湖是哪里 mysql索引建多了有什么坏处 索引有什么优缺点? MySQL索引过多会产生哪些问题 关于mysql建立索引需要注意的几点事项 数据库索引优缺点 MySQL数据库的索引的操作知多少 MySQL索引的缺点以及MySQL索引在实际操作中有哪些事项 OPPOr15x怎么看手机剩多少电池容量? 个人如何在银行开户? 我想开一家个人银行需要什么条件? 银行开户 必须是本人吗?可以代开吗? 个人去银行开户需要什么资料 本人银行卡是什么意思? 个人银行开户需要带什么资料 银行开户必须本人去吗 本人怎么查询本人在银行的资产情况。 本人开户银行指的是 还贷款必须本人亲自去银行还吗? 在银行办理个人业务,必须要本人去吗 学生本人银行账户填什么 mySQL的索引功能 如何将网页以微信图文的形式发出来? OPPO R15的续航能力,咋样,能坚持一天不 菜鸟驿站加盟电话 coolux微型投影仪怎么和手机连接 404 Not Found 酷乐视X6可以连接电脑吗? 404 Not Found 乐视电视外接音响怎么接线 华为mate7如何连接酷乐视投影仪 404 Not Found 在使用微型投影机酷乐视X3播放3D视频的时候,为什么有时候带上眼镜没有3D效果?怎么回事? 空调是变频好还是定频好? 格力空调变频与定频那个寿命长 格力挂机的变频空调是不是比变频的更加容易坏啊? Old Tom the killer whale,的翻译 格力空调变频好还是定频好? 家用空调买变频好还是定频好 OPPOR15充电需要多久才可以充满? 苹果拒绝参加反垄断听证会,表达出了什么?