原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

不啰嗦,直接入正题。问题是这样的。请问下面的sql语句,要想加快查询速度,该怎么创建索引?以下,以mysql数据库为准。

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

结果可能会出乎你的意料。我们首先准备一下运行环境,然后按照最左前缀原则和explain关键字来进行验证。结果真是颠覆了xjjdog多年的认知。

准备阶段

为了进行验证,我们创建一个简单的数据表。里面有a、b、c三个简单的int字段。

CREATE TABLE `test` (  `id` int(11) NOT NULL,  `a` int(11) DEFAULT NULL,  `b` int(11) DEFAULT NULL,  `c` int(11) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8

接下来,写一个简单的存储过程,来插入10w条数据。等待大约1分钟,数据插入完毕。

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

由于mysql有最左前缀原则,我们对abc三列进行了全排列,创建了6个索引。这6个索引涵盖了所有的根据abc查询的情况。

create INDEX idx_a_b_c on test(a,b,c);create INDEX idx_a_c_b on test(a,c,b);create INDEX idx_b_a_c on test(b,a,c);create INDEX idx_b_c_a on test(b,c,a);create INDEX idx_c_a_b on test(c,a,b);create INDEX idx_c_b_a on test(c,b,a);

使用Explain进行验证

1、自动选用索引

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

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

我们尝试换一下查询参数的位置。

 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。

 explain select * from testFORCE INDEX(idx_c_b_a)    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上有两个参数。

 explain select * from testFORCE INDEX(idx_b_c_a)where a>10   order by b,c

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

3、explain部分返回值意义

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

select_type
表示SELECT的类型,常见的取值有:

SIMPLE    简单表,不使用表连接或子查询。PRIMARY    主查询,即外层的查询。UNION    UNION中的第二个或者后面的查询语句。SUBQUERY    子查询中的第一个。

type
表示MySQL在表中找到所需行的方式,或者叫访问类型。常见访问类型如下,从下到上,性能越来越差。

system,const 表只有一行记录(等于系统表),这是const类型的特列。eq_ref 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。ref  非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。range 只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引。这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。index Full Index Scan,Index与All区别为index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。all 全表扫描,性能最差

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

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

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

End

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

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

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

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

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

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

作者简介:小姐姐味道  (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,进一步交流。

《必看!java后端,亮剑诛仙》
后端技术索引,中肯火爆

《Linux上,最常用的一批命令解析(10年精选)》
CSDN发布首日,1k赞。点赞率1/8。

《这次要是讲不明白Spring Cloud核心组件,那我就白编这故事了》
用故事讲解核心组件,包你满意

sql如何获取全部的索引名称_这句简单的sql,如何加索引?颠覆了我多年的认知...相关推荐

  1. sql server修改索引名称_索引基本知识和索引优化

    " 索引基本知识*哈希索引*组合索引*聚簇索引与非聚簇索引*覆盖索引*索引优化*索引监控*优化案例" 索引这个东西,个人的感觉是:平时大家都不怎么重视他,感觉哪个查询慢了就对那个列 ...

  2. sql server修改索引名称_【索引潜规则】覆盖索引、ICP、MRR详解

    点击上方蓝色字体,关注我们 上篇文章我们说了创建索引的方法,有聚簇索引.辅助索引.前缀索引.联合索引等,也说了如何利用索引的排序功能,接着本篇文章主要来说一说索引的几种优化策略,首先我们先说下回表的概 ...

  3. sql 非主键每年自增_或许你不知道的 10 条 SQL 技巧

    上文我们简述了 SQL 的一些进阶技巧,一些朋友觉得不过瘾,我们继续来下篇,再送你 10 个技巧 一. 使用延迟查询优化 limit [offset], [rows] 经常出现类似以下的 SQL 语句 ...

  4. mysql gis index 索引原理_从原理到优化,深入浅出数据库索引

    MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构. 数据库查询是数据库的最主要功能之一,我们都希望查询数据的速度能尽可能的快,因此数据库系统的设计者会从查询算法的 ...

  5. 实训1_获取产业数据并存储_预处理与简单分析

    目录 1. 实训一. 获取产业数据并存储.预处理与分析 1.1 实训内容概述 1.2 实训知识点: 1.2.1 爬取网页数据 1.2.1.1 一般格式 1.2.1.2 采用pandas读取网页表格数据 ...

  6. mysql 索引 美团_美团面试官:说说MySQL的索引

    从本文开始,选取牛客网上大厂的面试题,整理出相关内容的知识点. 什么是索引 小学时我们经常用到的字典里有音节索引和部首目录,当我们查字典时,常常用音节索引和部首目录帮助我们提高查找汉字的速度.MySQ ...

  7. mysql男女字段应该建立索引吗_为什么说性别字段不适合做索引?

    关于区分度不高的字段,比如性别,比如状态字段,是否应该建索引? 只有2种取值的字段,建了索引数据库也不一定会用,只会白白增加索引维护的额外开销,因为索引也是需要存储的,所以插入和更新的写入操作,同时需 ...

  8. 一句简单的SQL查询语句的背后...

    当我们在SQL Server Management Studio的查询里面输入: SELECT * FROM t1 WHERE c1=2; 背后发生了什么?数据库怎么去执行查询的? -  知其然不知其 ...

  9. easyexcel获取所有sheet页名称_老板让我汇总多个sheet,我不会,同事却说使用PQ仅需2步搞定...

    临近年底,老板总是会让我们汇总与统计很多数据,很多人都会在其身上花费大量的时间,今天就跟大家分享下如何快速完成数据汇总.数据汇总一般分为两类,多sheet汇总,以及多工作薄汇总,今天我们我能先来看一下 ...

最新文章

  1. git常见操作--忽略文件以及常用命令【转】
  2. github中删除已建仓库(二)
  3. iOS开发中地图与定位
  4. 企业如何抵御弱云密码带来的威胁
  5. softmax sigmoid
  6. Java 在Word中创建表格
  7. 学员_国培阶段性总结心得体会
  8. ICPC冠军教练亲自授课 字节跳动ICPC冬令营全球招募50支受训队
  9. 北京铁路安检全面升级 四大站特警持枪巡逻
  10. 通过百度BAE搭建微信二次开发的服务(2)
  11. vue + echarts 以山西地图为例
  12. Android 截屏并保存到本地(兼容Android 10.0)
  13. 在HarmonyOS中实现基于JS卡片的音乐播放器
  14. 记微信开发者工具登录网络连接失败
  15. 海盗分椰子c语言编程,水手分椰子——迭代法、递归解题(示例代码)
  16. web免登钉钉微应用
  17. Visual Studio Code的下载和安装
  18. android 群控 网络 adb,逍遥安卓模拟器群控软件用的ADB
  19. 2022-2028年中国城市物流车行业市场前瞻与投资战略规划分析报告
  20. ShaderLab 初学笔记

热门文章

  1. seata xid是什么_Seata 分布式事务框架
  2. 关于Java基础需要注意的点
  3. A53 cache的架构解读
  4. 位运算符实现加法和乘法
  5. angr学习笔记(13)(static_binary)
  6. [web安全]深入理解反射式dll注入技术
  7. window下pip 用不了的一种解决办法
  8. Windows事件等待学习笔记(三)—— WaitForSingleObject函数分析
  9. 栈的应用_中缀表达式转后缀表达式
  10. 【Docker】日常记录