首先先建立数据库和插入数据

我们要查询的命令如下,前提是以mysql数据库为准

  1. select * from test where a=? and b>? order by c limit 0,100

结果和我想的不太一样,先准备好环境和所需的数据库和表

准备阶段

  1. CREATE TABLE `test` (
  2. `id` int(11) NOT NULL,
  3. `a` int(11) DEFAULT NULL,
  4. `b` int(11) DEFAULT NULL,
  5. `c` int(11) DEFAULT NULL,
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8

准备插入数据

  1. DROP PROCEDURE IF EXISTS test_initData;
  2. DELIMITER $
  3. CREATE PROCEDURE test_initData()
  4. BEGIN
  5. DECLARE i INT DEFAULT 1;
  6. WHILE i<=100000 DO
  7. INSERT INTO test(id,a,b,c) VALUES(i,i*2,i*3,i*4);
  8. SET i = i+1;
  9. END WHILE;
  10. END $
  11. CALL test_initData();

由于mysql有最左前缀规则,对abc进行排列,创建6个索引,涵盖了全部查询的情况(就是全部查询abc)

  1. create INDEX idx_a_b_c on test(a,b,c);
  2. create INDEX idx_a_c_b on test(a,c,b);
  3. create INDEX idx_b_a_c on test(b,a,c);
  4. create INDEX idx_b_c_a on test(b,c,a);
  5. create INDEX idx_c_a_b on test(c,a,b);
  6. create INDEX idx_c_b_a on test(c,b,a);

使用EXplain验证

1、自动选用索引

  1. explain select * from test where a>10 and b >10 order by c

首先,我们拿上面的sql语句进行验证。结果发现,查询使用了索引idx_a_b_c,只用到了前缀a,b。而extra部分,则用到了filesort,也就是性能非常差的方式。

可有换一下查询参数的位置

  1. explain select * from test where c>10 and b >10 order by a

可以看到这次自动选择了idx_b_a_c,但依然使用的filesort,查询效果是一样的。按照上面的逻辑,不是应该选择idx_b_c_a么?

2、指定索引

我们采用使用force index方式,强制指定索引。 这里直接给出结果,就是下面的sql。

  1. explain select * from test
  2. FORCE INDEX(idx_c_b_a)
  3. where a>10 and b >10 order by c

结果为:

我们使用force index来指定使用的索引。这次效果非常好,显示使用了index,使用了where,只在索引上就完成了操作。但扫描的行数却增加了。

但是,这与我们的经验是相悖的。idx_c_b_a的索引,是在字段(c,b,a)上创建的。按照最左原则,支持的搜索条件有:c,cb,cba。在这个例子中,order by后面的参数,却被当作了前缀的头部信息。

我们删掉其他索引,只留下idx_c_b_a,然后去掉force index部分。结果发现,mysql现在能够自动的选择索引了。

还有另外一种情况,order by 上有两个参数。

  1. explain select * from test
  2. FORCE INDEX(idx_b_c_a)
  3. where a>10 order by b,c

结果:

使用idx_b_c_a,不走filesort,其他索引都不是最优。

3、explain部分返回值意义

可以得出上面的结论,是根据mysql自己提供的explain工具,这个工具可以输出一些有用的信息,下边是部分返回值的意义。

  1. select_type
  2. 表示SELECT的类型,常见的取值有:
  3. SIMPLE 简单表,不使用表连接或子查询。
  4. PRIMARY 主查询,即外层的查询。
  5. UNION UNION中的第二个或者后面的查询语句。
  6. SUBQUERY 子查询中的第一个。
  7. type
  8. 表示MySQL在表中找到所需行的方式,或者叫访问类型。常见访问类型如下,从下到上,性能越来越差。
  9. system,const 表只有一行记录(等于系统表),这是const类型的特列。
  10. eq_ref 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。
  11. ref 非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
  12. range 只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引。这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。
  13. index Full Index ScanIndexAll区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。
  14. all 全表扫描,性能最差
  15. Extra
  16. using index
  17. 表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,效率不错。如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
  18. using filesort
  19. 说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序”。
  20. using temporary
  21. 使用了用临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于排序order by和分组查询group by

最后

可以看到,在我们创建了多个索引的时候,mysql的查询优化,并不一定能够进行智能的解析、用到最优的方式,需要使用force index指定索引。

mysql中的索引,主要就用在where条件中和排序动作中。分两种情况。

1、先过滤,再排序,会用到过滤条件中的索引参数,但是排序会使用较慢的外部排序。因为这个结果集是经过过滤的,并没有什么索引参与。

2、先排序,再过滤,可以使用同一个索引,排序的优先级高于过滤的优先级。选择合适的索引,在过滤的同时就把这个事给办了。但是扫描的行数会增加。

我想,mysql并不能够了解到这两个过程,到底谁快谁慢,于是选了一个最通用的方式,直接选用了第一种。甚至在索引非常多的时候,直接晕菜了。**索引建多了,你可能间接把mysql给害了。**这是现象,至于深层次的原因,欢迎读过mysql相关源码的给解释一下。

这对经常变换字段进行排序的代码来说,并不是一个好的信号。考虑到程序的稳定性,我想应该要尽量减少where条件过滤后的结果集。这种情况下,创建一个(a,b)的联合索引,或许是一个折衷的方式。

以上内容转载于   https://juejin.im/post/5d6881d4f265da03ab426341

记一次sql索引颠覆认知的更多相关文章

  1. 数据库性能优化:SQL索引

    SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱. 1.1 什么是索引? SQL索引有两种,聚集索引和非聚集索引 ...

  2. SQL索引一步到位

    以下均非原创,仅供分享.学习!!! SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱. 1.1 什么是索引? S ...

  3. {好文备份}SQL索引一步到位

    SQL索引一步到位(此文章为"数据库性能优化二:数据库表优化"附属文章之一)   SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百 ...

  4. 转载:SQL索引一步到位

    原文: http://www.cnblogs.com/AK2012/archive/2013/01/04/2844283.html SQL索引一步到位(此文章为“数据库性能优化二:数据库表优化”附属文 ...

  5. SQL索引一步到位(此文章为“数据库性能优化二:数据库表优化”附属文章之一)

    SQL索引一步到位(此文章为“数据库性能优化二:数据库表优化”附属文章之一) SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭 ...

  6. SQL索引详解

    转自:http://www.cnblogs.com/AK2012/archive/2013/01/04/2844283.html SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可 ...

  7. 数据库性能优化一:SQL索引一步到位

    SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱. 1.1 什么是索引? SQL索引有两种,聚集索引和非聚集索引 ...

  8. 【转】SQL索引一步到位

    原文:http://www.cnblogs.com/AK2012/archive/2013/01/04/2844283.html SQL索引一步到位(此文章为“数据库性能优化二:数据库表优化”附属文章 ...

  9. SQL索引学习-索引结构

    前一阵无意中和同事讨论过一个SQL相关的题(通过一个小问题来学习SQL关联查询),很惭愧一个非常简单的问题由于种种原因居然没有回答正确,数据库知识方面我算不上技术好,谈起SQL知识的学习我得益于200 ...

随机推荐

  1. BZOJ 1233 干草堆 (单调队列优化DP)

    $ BZOJ~1233~~ $ 干草堆: (题目特殊性质) $ solution: $ 很妙的一道题目,开始看了一眼觉得是个傻逼贪心,从后往前当前层能多短就多短,尽量节省花费.但是这是DP专题,怎么会 ...

  2. File类常用方法和枚举

    新建一个file对象: File f = new File("F:\\01.JAVA基础300集\\05_常用类\\122.File类的使用.mp4"); (文件路径也可以用&qu ...

  3. POJ 3784 Running Median (动态中位数)

    题目链接:http://poj.org/problem?id=3784 题目大意:依次输入n个数,每当输入奇数个数的时候,求出当前序列的中位数(排好序的中位数). 此题可用各种方法求解. 排序二叉树方 ...

  4. 调试IPV6

    从Mac分享IPV6 WIFI的方法: 按住opition + 系统设置中的share 进入 如果被拒了要上诉或者回复审核团队邮件,可以参考这个写: 尊敬的APP审查委员会: 您们好!我们希望将自己开 ...

  5. 数字类别生成onehot

    对应行的列#原始标签 my_label = np.array([3,4,2,4,6,1]) #类别数量 num_class = 6 #样本数量 num = my_label.shape[0] #生成o ...

  6. 【CF1257C】Dominated Subarray【贪心】

    题意:给定一个数组,求最小的字数组使得数组里存在至少一对重复元素 题解:每个点求出他的后继在哪,然后每次贪心就这个点到他的后继为一个子数组,求出最小的就是答案 #include<iostream ...

  7. Python_008(文件操作)

    一.文件操作 1.只读操作 f = open("taibai.txt",mode = "r",encoding = "utf-8" s = ...

  8. Largest Point

    Largest Point Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  9. String Problem

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  10. MyBatis3学习笔记(曹锋老师版)

    第2讲 这一讲主要讲解了 Mybatis 的主配置文件. 下面是一个示例的配置文件: <?xml version="1.0" encoding="UTF-8&quo ...