御丽诗妃谈MySQL索引怎么用

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

追逐仰望星空 2020-08-05 10:43:38

推荐学习

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

 

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

索引使用的优点

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

具体会有多快呢?sql

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

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

 

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

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

 

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

索引使用的劣势

凡事具备两面性,有好就会有坏,拿时间换空间或者拿空间换时间这种操做家常便饭,索引就是拿空间换时间,虽然并非那么典型(由于它核心并非增大空间减小时间,而是经过维护相似目录的结构减小IO的读写次数,最典型的空间换时间是计数排序)。坏处天然就出现了:函数

一、维护成本高

索引维护了一个相似于目录的结构,你能够联想新华字典的目录,当你建立目录的时候,若是没有程序帮忙,你本身手写目录的话,须要一页一页的去翻去看肯定那个字在哪儿,而后写进目录里;万一有个字被删了或者加了一个字还要从新调整一遍目录。对程序也是同样,索引的建立和维护是须要消耗性能的,因此会下降数据库修改时的性能。就以建立索引来讲,建立百万级别的varchar数据BTREE索引,数据内容长度为20个汉字,消耗的时间为61.234s:oop

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

 

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

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

 

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

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

 

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

二、所占空间大

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

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

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

 

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

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

 

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

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

索引的分类

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

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

索引的建立规则

索引既然有这么明显的优点以及劣势,咱们天然要把它的优点最大化,劣势尽量避免。因此索引最好能作到:

一、常常做为查询或者排序条件;

二、重复值尽量少;

三、增删改不会太多。

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

因此总结一下适合建立的状况(就是以上面三个条件做为参考的各类状况啦):

一、主键:主键是自动创建惟一索引的,不用咱操心;二、频繁做为查询条件的字段:毕竟就是为了查的快才建立索引的嘛;三、查询中与其它表关联的字段:这就是外键了,不只关联查询用到了,重复值不多,很棒;四、若是有多个字段,尽可能建立组合索引:当查询优化器以为分析两个查询索引太费劲了,还不如用一个的时候,它就给你用一个,因此只要遵循最佳左前缀原则,仍是组合索引更靠谱;五、查询中排序的字段:排序字段若经过索引去访问将大大提升排序速度;六、查询中统计或者分组字段:和上面状况同样啦。

那何时不适合建立呢:

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

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

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

索引的CRD没有U

建立Create

#该语句添加一个主键,这意味着索引值必须是惟一的,且不能为NULLALTER 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的写法来达到选择合适索引的目的。

相关文章
相关标签/搜索