您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

时间:2020-08-05 14:30:11  来源:  作者:

 

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

为了能让索引能有更直观的效率,我在一张表里扔进了百万条数据(光靠这些数据,生成数据代码写了一个小时,解决MySQL8的文件导入权限问题解决了两个小时,导入数据花费了一个小时,我太难了~(;д;)。但是,一切不以实践数据为标准的理论都是**耍!流!氓!**o(´^`)o)。让我们一边讲解MySQL的使用一边看一下索引能为我们的查询带来的性能提升吧。

索引使用的优势

提高查询效率,简单来说就是查的再快更快!外面说的什么提高表的速度、加速表连接、减少分组及排序时间、提高系统性能,说白了都是快,查得快!(顺便我发现百度出来的索引使用优势劣势貌似就那么一两套,真就天下文章一大抄呗,抄我的也欢迎,烦请注明出处或者作者Solid_lele哈)

具体会有多快呢?

这是没有索引的百万级数据查找(这个算快的了,慢的四十秒,时间不是很稳定,因为是从磁盘块中读取数据,原理参照我开头提到的那篇文章)10.797s:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

这是有索引的百万级数据查找0.272s:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

差了四十多倍,就相当于别人一年赚四十多万,我一年赚一万,这差距真的是太痛苦了。

索引使用的劣势

凡事具有两面性,有好就会有坏,拿时间换空间或者拿空间换时间这种操作屡见不鲜,索引就是拿空间换时间,虽然并不是那么典型(因为它核心并不是增大空间减少时间,而是通过维护类似目录的结构减少IO的读写次数,最典型的空间换时间是计数排序)。坏处自然就出现了:

1、维护成本高

索引维护了一个类似于目录的结构,你可以联想新华字典的目录,当你创建目录的时候,如果没有程序帮忙,你自己手写目录的话,需要一页一页的去翻去看确定那个字在哪儿,然后写进目录里;万一有个字被删了或者加了一个字还要重新调整一遍目录。对程序也是一样,索引的创建和维护是需要消耗性能的,所以会降低数据库修改时的性能。就以创建索引来说,创建百万级别的varchar数据BTREE索引,数据内容长度为20个汉字,消耗的时间为61.234s:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

再比较一下维护索引的代价,比如无索引百万级别数据插入一条时间为0.480s:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

而有索引的百万级别数据插入一条时间为1.273s:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

差距其实还挺大的(请忽略我乱打插入的三个字)。

2、所占空间大

既然提到空间换时间,那么空间的浪费是不可避免的,我做了下面的这个测试(测试数据库MySQL8,数据库运行环境windows)。

首先创建了一个临时表tmp_name,其中只有一列名为c_name的字段,发现文件夹中存储的ibd文件初始大小为112k,插入百万条数据(100万条数据整哦,一个不多一个不少哦)后,大小为40960k:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

然后创建了一个BTREE索引,大小变为了73728k:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

大约多用了一倍的空间。但实际中不可能每个字段都加索引,生产中为索引预留的空间大概占数据大小的五分之一就够了。在这个数据为重效率至上的时代,磁盘的空间成本貌似还是比较划算的。

其实使用索引还有个劣势,就是你需要花费时间来看我这篇文章o(////▽////)q

索引的分类

单值索引:就是一个索引只包含单个列,一个表可以有多个单列索引;唯一索引:就是索引列的值必须唯一,但允许有空值(主键索引就是唯一索引,但它不能为null);复合索引:就是联合索引,也就是一个索引包含多个列;

我看网上介绍索引的都说了唯一索引和复合索引,咋,单值索引就不算索引了?互相“借鉴”的时候好歹也自己思考一下好不啦。

索引的创建规则

索引既然有这么明显的优势以及劣势,我们自然要把它的优势最大化,劣势尽可能避免。所以索引最好能做到:

1、经常作为查询或者排序条件;

2、重复值尽可能少;

3、增删改不会太多。

满足上面三条规则的就可以创建索引了(不符合规则怎么样这种数据我实在是不想贴出来了,就直接说吧,这篇文章到现在算上造数据+各种实验写了十个小时了,还没结束,又赶上LOL的无限火力,明明是周末却只能羡慕别人在玩的我很是痛苦哇)。

所以总结一下适合创建的情况(就是以上面三个条件作为参考的各种情况啦):

1、主键:主键是自动建立唯一索引的,不用咱操心;2、频繁作为查询条件的字段:毕竟就是为了查的快才创建索引的嘛;3、查询中与其它表关联的字段:这就是外键了,不仅关联查询用到了,重复值很少,很棒;4、如果有多个字段,尽量创建组合索引:当查询优化器觉得分析两个查询索引太费劲了,还不如用一个的时候,它就给你用一个,所以只要遵循最佳左前缀原则,还是组合索引更靠谱;5、查询中排序的字段:排序字段若通过索引去访问将大大提高排序速度;6、查询中统计或者分组字段:和上面情况一样啦。

那什么时候不适合创建呢:

1、表记录太少而且不会变得很多:夭寿啦,就这么几百条数据建索引不如直接查一遍;

2、频繁更新的字段不适合创建索引:维护索引很累的,查的没这么多但是总改总改,系统就像被经常需求变动的程序员,不跟你打起来就不错了;

3、Where条件里用不到的字段不创建索引:不要问为什么,问就是出门左转是电梯;

索引的CRD没有U

创建Create

#该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE [table_name] ADD PRIMARY KEY ([column_list]);
#这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE [table_name] ADD UNIQUE [index_name] ([column_list]);
#添加普通索引,索引值可出现多次。
ALTER TABLE [table_name] ADD INDEX [index_name] ([column_list]);
#该语句指定了索引为 FULLTEXT ,用于全文索引。
ALTER TABLE [table_name] ADD FULLTEXT [index_name] ([column_list]);

查看Read

SHOW INDEX FROM [table_name];

删除Drop

DROP INDEX [index_name] ON [table_name];

更新,不好意思没有,想改就是删了重加。

索引的分析(Explain)

终于走到这儿了,真刀真枪打一架吧,前面都是开胃小菜,现在才是正餐,但估计你们都快吃饱了,我也做累了,就很尴尬。

Explain是什么

话不多说,看官网API说明:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

The EXPLAIN statement provides information about how MySQL executes statements. EXPLAIN works with SELECT, DELETE, INSERT, REPLACE, and UPDATE statements.

EXPLAIN returns a row of information for each table used in the SELECT statement. It lists the tables in the output in the order that MySQL would read them while processing the statement. MySQL resolves all joins using a nested-loop join method. This means that MySQL reads a row from the first table, and then finds a matching row in the second table, the third table, and so on. When all tables are processed, MySQL outputs the selected columns and backtracks through the table list until a table is found for which there are more matching rows. The next row is read from this table and the process continues with the next table.

EXPLAIN语句提供了关于MySQL怎样执行语句的信息。EXPLAIN可以用来分析SELECT、DELETE、INSERT、REPLACE和UPDATE语句。EXPLAIN为SELECT语句中使用的每个表返回一行信息。它按照MySQL在处理语句时读取的顺序,列出执行输出中的表。MySQL使用嵌套循环连接方法解析所有连接。这意味着MySQL从第一个表中读取一行,然后在第二个表、第三个表中找到匹配的行,以此类推。当处理完所有表后,MySQL将输出所选的列,并通过表列表进行回溯,直到找到一个具有更多匹配行的表为止。从该表读取下一行,然后继续处理下一个表。

说白了就是能让你看表的读取顺序、用索引情况、表之间的引用、优化器查询的情况这些信息的执行情况分析。(不允许说每个汉字都认识凑到一起不知道啥意思了)

Explain的使用及分析

使用:就是Explain+你的sql语句:

EXPLAIN SELECT * FROM t_solid_test where c_name = 'Solid';

查询出来长这个样子:

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

这么多信息都代表什么?咱一个个来看。

id

select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序。

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

id值越大,优先级越高,越先执行;id如果相同,从上往下顺序执行。

select_type

查询类型

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

SIMPLE:简单的 select 查询,查询中不包含子查询或者UNION;

PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为;

UNION:若第二个SELECT出现在UNION之后,则被标记为UNION; 若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED;

DEPENDENT UNION:一个UNION中的第二个或更高版本的SELECT语句 ,取决于外部查询;

UNION RESULT:UNION的结果。

SUBQUERY:在SELECT或WHERE列表中包含了子查询;

DEPENDENT SUBQUERY:在子查询中的第一个SELECT,取决于外部查询

DERIVED:在FROM列表中包含的子查询被标记为DERIVED(衍生) MySQL会递归执行这些子查询, 把结果放在临时表里;

DEPENDENT DERIVED:派生表依赖于另一个表;

MATERIALIZED:物化子查询;

UNCACHEABLE SUBQUERY:子查询,其结果无法缓存,必须针对外部查询的每一行重新进行评估;

UNCACHEABLE UNION:UNION 属于不可缓存子查询的中的第二个或更高版本的选择(请参阅UNCACHEABLE SUBQUERY的参考资料 );

partitions

查询分区的匹配记录。如果未分区则为NULL;

table

显示这一行的数据是关于哪张表的;

type

访问类型排列, 显示查询使用了何种类型:

system:表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计。

const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快 如将主键置于where列表中,MySQL就能将该查询转换为一个常量。

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。

ref:非唯一性索引扫描,返回匹配某个单独值的所有行. 本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而, 它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。

fulltext:使用FULLTEXT 索引执行联接。

ref_or_null:这种连接类型类似于 ref,但是除了MySQL会额外搜索包含NULL值的行。

index_merge:此联接类型指示使用索引合并优化。在这种情况下,key输出行中的列包含所用索引的列表,并key_len包含所用索引 的最长键部分的列表。有关更多信息,请参见 第8.2.1.3节“索引合并优化”。

unique_subquery:此类型替换 以下形式的eq_ref某些 IN子查询:value IN (SELECT primary_key FROM single_table WHERE some_expr),unique_subquery 只是一个索引查找函数,它完全替代了子查询以提高效率。

index_subquery:此连接类型类似于 unique_subquery。它代替IN子查询,但适用于以下形式的子查询中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)。

range:只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引 一般就是在你的where语句中出现了between、<、>、in等的查询 这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。

index:Full Index Scan,index与ALL区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小(也就是说虽然all和Index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)。

all:Full Table Scan,将遍历全表以找到匹配的行。备注:一般来说,得保证查询至少达到range级别,最好能达到ref。

possible_keys

显示可能应用在这张表中的索引,一个或多个。 查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

key

实际使用的索引。如果为NULL,则没有使用索引。查询中若使用了覆盖索引,则该索引和查询的select字段重叠。

key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。

rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。

Extra

包含不适合在其他列中显示但十分重要的额外信息:

Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序”。

Using temporary:使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序order by 和分组查询 group by。

USING index:表示相应的select操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错! 如果同时出现using where,表明索引被用来执行索引键值的查找; 如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。

Using where:表明使用了where过滤。

using join buffer:使用了连接缓存。

impossible where:where子句的值总是false,不能用来获取任何元素。

select tables optimized away:在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算, 查询执行计划生成的阶段即完成优化。

distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作

索引使用案例

最理想的情况

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

最佳左前缀原则

后台创建的索引是name_sex_age的联合索引,联合索引中,从左往右匹配,如果最开始匹配不到,则索引失效。

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 


MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 


MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

尽量不用函数操作索引

在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描。

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

索引中范围条件右边的列不会被使用

下面这个联合索引,当联合索引中间的值查询条件为范围查询时,右侧的索引不会被用到。

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 


MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 


MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

少用select *

尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select *。

MySQL索引怎么用?究竟能有多快?看完这篇你就懂了

 

索引失效的几个情况

不等于(!= 或者<>)、is null、is not null 、or、like以通配符开头(’%abc…’)、字符串不加单引号(类型转换)

这就不贴图了,没啥可贴的,用了type就是ALL;

索引使用的总结建议

最后,给一个索引使用的总结吧:

对于单键索引,尽量选择针对当前query过滤性更好的索引。在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。在选择组合索引的时候,尽量选择可以能够包含当前query中的where字句中更多字段的索引。尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的。

作者:Solid-Snaker

原文链接:https://blog.csdn.net/jcSongle/article/details/106133005



Tags:MySQL索引   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
Mysql索引数据结构下面列举了常见的数据结构 二叉树 红黑树 Hash表 B-Tree(B树)Select * from t where t.col=5我们在执行一条查询的Sql语句时候,在数据量比较大又不加索引的情...【详细内容】
2021-06-07  Tags: MySQL索引  点击:(90)  评论:(0)  加入收藏
聊聊Mysql索引和redis跳表 ---redis的有序集合zset数据结构底层采用了跳表原理 时间复杂度O(logn)(阿里)redis使用跳表不用B+数的原因是:redis是内存数据库,而B+树纯粹是为了m...【详细内容】
2021-02-05  Tags: MySQL索引  点击:(190)  评论:(0)  加入收藏
本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题。特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引...【详细内容】
2020-08-16  Tags: MySQL索引  点击:(55)  评论:(0)  加入收藏
为了能让索引能有更直观的效率,我在一张表里扔进了百万条数据(光靠这些数据,生成数据代码写了一个小时,解决MySQL8的文件导入权限问题解决了两个小时,导入数据花费了一个小时,我...【详细内容】
2020-08-05  Tags: MySQL索引  点击:(66)  评论:(0)  加入收藏
概述随着电商的发展,使用数据库的业务越来越复杂,除了掌握哪些场景可以使用索引,哪些场景适合使用索引,还需要掌握索引在运行过程中的一些使用规则,特别是组合索引的使用。比如索...【详细内容】
2020-07-06  Tags: MySQL索引  点击:(54)  评论:(0)  加入收藏
1 初识索引索引在MySQL中也叫是一种“键”,是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发...【详细内容】
2019-11-18  Tags: MySQL索引  点击:(95)  评论:(0)  加入收藏
概述在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页...【详细内容】
2019-09-12  Tags: MySQL索引  点击:(130)  评论:(0)  加入收藏
在我们使用MySQL的过程中,随着数据量越来越大,查询显得有些吃力,这时候就要针对查询就行优化,针对查询优化,通过给字段添加索引可以提高数据的读取速度,提高项目的并发能力和抗压...【详细内容】
2019-09-07  Tags: MySQL索引  点击:(100)  评论:(0)  加入收藏
索引是一种用于快速查询行的数据结构,就像一本书的目录就是一个索引,如果想在一本书中找到某个主题,一般会先找到对应页码。在mysql中,存储引擎用类似的方法使用索引,先在索引中...【详细内容】
2019-09-05  Tags: MySQL索引  点击:(277)  评论:(0)  加入收藏
索引目的索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么你可能需要把...【详细内容】
2019-08-29  Tags: MySQL索引  点击:(186)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(6)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(17)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(16)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(20)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(31)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(27)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条