Mysql优化之索引

前言

  这几天抽了个时间将《高性能Mysql》看了一下忽觉索引很是之重要,习之而后总结巩固知识。本文索引使用的是InnoDB存储引擎。由于本文并非说用索引的好处,因此并不会书写QPS之类的测试结果请你们见谅。个人mysql版本是8.0.11。mysql

目录

  (一)索引使用优化sql

      ①独立的列数据库

                  ②覆盖索引函数

                  ③索引匹配性能

  (二)索引建立优化学习

      ①前缀索引和索引选择性测试

                   ②选择合适的索引顺序优化

                   ③不建立冗余和重复索引3d

索引使用优化

  咱们有时候虽然建立了合适的索引可是使用不当依然会使索引失效,因此我将书上的索引使用大体总结了一下。在这以前我先介绍一下EXPLAIN生成结果中字段type和Extra的意义,先说一下type常出现的结果。blog

  (1)const 表中最多只有一行用于主键和惟一索引的匹配

  (2)all全表扫描

  (3)ref使用索引并符合最左匹配

  (4)index :❶

      a.当查询是索引覆盖的,即全部数据都可从索引树获取的时候(Extra中有Using Index);

      b.以索引顺序从索引中查找数据行的全表扫描(无 Using Index);

      c.若是Extra中Using Index与Using Where同时出现的话,则是利用索引查找键值的意思;

      d.如单独出现,则是用读索引来代替读行,但不用于查找

  接下来咱们解释一下Extra出现的结果:

   (1)using index 使用覆盖索引。

   (2)using where 条件语句中部分条件使用的是索引,其余条件须要去表中筛选。

   (3)using inex condition 条件语句中全部条件都在索引中,可是所须要的数据不在索引中。

   (4)using where;using index 条件和所需数据都在索引中。

 独立的列

  独立的列一眼上看去觉得是针对于一个单独的列建立索引可是实际上并非这样的。“独立的列”是指索引列不能是表达式的一部分,也不能是函数的参数❷。这句话的前面一句话在书上是:若是使用独立的列则mysql不会使用索引。这句话有点模棱两可,“不会使用索引”究竟是包括索引全扫描仍是不包括索引全扫描,若是包括的话则与实验结果不相符,若是不包括的话那就没问题了。废话很少说仍是用结果来证实吧。首先个人数据库表结构是这样子的,以下图所示:

  

  我建立了两个单独列的索引用来测试表达式和函数以下图所示:

  

       

  测试sql: explain select age  from user where age =2;

  

  从测试结果中咱们能够看到type为ref(使用BTree索引),Extra为Using index(使用了覆盖索引)

  若是咱们把sql语句改成: explain select age from user where age+1=2;解释结果以下所示:

  

  能够看到这条查询语句是使用了索引的,不过是扫描索引的所有数据。接下来测试一下若是条件语句中使用了函数是否会使用索引个人sql语是:EXPLAIN SELECT id from user where TO_DAYS(birthday) >= 50000000;测试结果以下图所示:

  

  OK,结果也是index。至于书上那句话是对是错我就不得而知了,不过你们能够本身去测试一下。

 

 

 覆盖索引

  若是把使用索引比做你开了一辆五菱宏光的话,那么你使用覆盖索引就是开了一辆兰博基尼(兰博基尼的性能是由你本身来决定的)。覆盖索引简单的来说就是你所要查询的字段和条件语句都在一条索引中。接下来又是证实的过程,我建立一个新的索引以下图所示:

  

  而后我使用这条sql语句 EXPLAIN SELECT first_name,age from user where  first_name='张' and age >0,在这条sql语句中我查询两个不一样索引中的列查询结果以下所示;

  

  在这条sql语句中我使用了两个索引idx_fk_name和idx_fk_age,查询的列和查询条件都是在这两个索引中,测试的结果为using where(须要回表查询所须要的数据)。接下来咱们使用这个sql语句 EXPLAIN SELECT last_name FROM user where first_name = '张',使用结果以下图所示:

      

 

 索引匹配

  若是咱们书写的sql语句符合索引匹配原则,那么咱们就能够不进行索引的所有数据扫描,结果就是咱们的查询效率又变高了。那么索引匹配原则是啥?我就简略的总结一下吧。

    全值匹配

  全值匹配就是查询条件和索引中的全部列进行匹配。如我上面建立的idx_fx_name索引。select * from user where first_name='张' 和 last_name = '三' 这条sql语句就是全值匹配。注意若是写成last_name='三' and first_name='张'也是全值匹配

  最左匹配

   我把书中匹配最左前缀和匹配列前缀都划分为最左匹配,由于我以为它都是从最左边开始匹配的,好像网上也是这么说的。

  最左前缀就是你写的条件查询语句针对于某个索引来讲它符合从左边一个一个进行匹配的方式(通过实测条件语句的顺序不影响最左匹配的原则),再拿个人idx_fx_name索引来举个例子。如select * from user where last_name = '三'和 select * from user where first_name = '张' 这两个sql语句查询索引的方式都不同,前者是扫描索引全部数据,第二个就只扫描了索引的部分数据。测试结果以下所示:

  

  

  匹配范围值

   在符合最左匹配的基础上可使用范围进行查询。

   精确匹配加范围匹配

    在符合最左匹配的基础上最后一个查询条件能够记性范围查询。

  

 索引建立优化

  前缀索引和索引选择性

   咱们先说说索引的选择性吧。索引的选择性是指不重复的索引值(也称为基数,cardinality)和数据表的记录总数(#T)的比值,范围从1/#T到1之间❸。这句话通俗的理解就是你选择做为索引(固然是只能选择某个字段,字段的所有或者部分)的数据在表中这个字段列中重复率越低越好,由于这样能够过滤更多的数据行。前缀索引就是能够拿某个字段的前缀做为索引之因此把前缀因此和索引选择性放到一块儿说是为了解决当咱们选择一个特别长的字段做为索引时首先会很浪费空间其次是查询的时候速度确定会比较慢。

    那么咱们怎么计算索引选择性的高低呢?这个有方法的,方法就是经过关键字DISTINCT 和 Count来计算索引的选择性。如我计算first_name的选择性高低能够这样计算:

   select count(DISTINCT first_name) / count(1) as a1 from user;

   若是我要计算以first_name前三个字符做为索引的话计算选择性能够这样写:

   select count(DISTINCT LEFT(first_name,3)) / count(1) as a1 from user;

   经过不断的修改所包含的前缀的大小咱们就能找到选择性高的索引。

   选择合适的索引序列

    其实选择合适的索引序列我以为根据实际状况来作分析。不过通常来讲咱们都把选择性高的放在前面,其余的就是要根据where子句中的排序、分组和范围条件等其余因素来选择索引的序列

   不建立冗余和重复的索引

    这里有两个问题摆在咱们的面前什么是冗余的索引?什么是重复索引?

   重复索引:具备相同列的索引就是重复索引。如(A,B)和(B,A)就是重复索引。

   冗余索引:一个索引的子集就是冗余索引。如(A,B,C) 和(A,B) (B,C)就是冗余索引。

   从通常状况来讲就是尽可能不建立重复索引和冗余索引,可是在特殊的状况下咱们能够建立冗余索引。

 

总结

  以上就是我学习《高性能mysql》书籍的总结。若是有什么问题请你们及时反馈给我毕竟互相交流才能促进学习。

借鉴书籍或博客

❶http://blog.51cto.com/lijianjun/1881208

❷《高性能mysql》第五章第三节

❸《高性能msql》第五章第三节第二小节

相关文章
相关标签/搜索