作者 | 曹建

责编 | 屠敏

出品 | CSDN(ID:CSDNnews)

我们都知道创建索引的目的是快速从整体集合中选择性地读取满足条件的一部分集合。MySQL中一张表是可以支持多个索引的。但是,你写SQL语句的时候,并没有主动指定使用哪个索引。不知道你有没有碰到过这种情况,一条创建了索引的SQL语句在查询过程中却没有使用索引,或是一条本来可以执行的很快的语句,却由于MySQL选错了索引,而导致查询速度变得很慢?充分优化和利用索引能够大大提高数据的查询效率,但是在实际的应用中MySQL可能并不总会选择合适且效率高的索引。那么我们今天就一起来讨论下 MySQL 索引以及索引的优化,首先我们来看一个案例,下面是一张建表的SQL如下:

CREATE TABLE `t_test3` (`id` bigint(11) NOT NULL,`name` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`),KEY `t_test_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf-8;

使用以下的SQL查看对应的执行计划:

desc select * from t_test3 where  name in ('a','b');

事实上,在建立表的sql中我们是对name这一列建立了索引,为何在执行计划的时候没有使用索引呢?

要找到这个原因,我们需要首先了解下SQL在mysql中的执行过程,MYSQL 的整个架构可以分为 server 层 和存储引擎层2个部分。Server 层 包括连接器,查询缓存,分析器,优化器,执行器等模块; 存储引擎层 负责数据的存储与提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎,默认的是InnoDB。可以在建表的时候使用engine = memory来指定存储引擎 。

其中Server 层执行步骤如下:

第一步连接器:通过账号和密码连接到对应的数据库上,连接器负责与客户端建立连接,获取权限,维持和管理连接。连接分为长连接和短连接,长连接是指连接成功后,客户端不断有请求,则一直使用同一个连接。短连接:处理几个请求后,断开连接,之后的请求需要重新连接。

第二步查询缓存:建立连接之后,mysql拿到一个查询请求后,会先查询缓存中之前是否执行过这条语句,如果查询缓存命中,则查询结果直接返回给客户端,如果查询缓存不命中,就会继续后面的执行阶段。完成以后,执行结果会被存入查询缓存中。大多数情况下不建议使用查询缓存。如果缓存命中,mysql不需要执行后面的复杂操作,就可以直接返回结果,效率很高,但是查询缓存失效非常频繁,只要有对一个表的更新,这个表的所有查询缓存都会被清空,因此可能你费力地把结果缓存起来,还没使用,就被一个更新全部清空了。除非你的业务是一张静态表,很长时间才会更新一次,这种情况下可以使用查询缓存。

第三步分析器:mysql在执行之前,首先会对sql语句做词法解析和语法解析,以确定你要做什么,并会识别语句中的关键词,比如select,order by等,以及解析sql语法是否正确等。

第四步优化器:优化器是数据库的一个核心子系统,你也可以把他理解为 MySQL 数据库中的一个核心模块或者一个核心功能模块。优化器的目的是按照一定原则来得到它认为的目标SQL在当前情形下最有效的执行路径,优化器的目的是为了得到目标SQL的执行计划。经过分析器,mysql就知道你要做什么了。SQL 在执行的过程中经过优化器,并由优化器生成 SQL 的执行计划。

传统关系型数据库里面的优化器分为CBO和RBO两种:

  • RBO--- Rule_Based Potimizer 基于规则的优化器:RBO所用的判断规则是一组内置的规则,这些规则是硬编码在数据库的编码中的,RBO会根据这些规则去从SQL诸多的路径中来选择一条作为执行计划(比如在RBO里面,有这么一条规则:有索引使用索引。那么所有带有索引的表在任何情况下都会走索引)所以,RBO现在被很多数据库抛弃(oracle默认是CBO,但是仍然保留RBO代码,MySQL只有CBO),RBO最大问题在于硬编码在数据库里面的一系列固定规则,来决定执行计划。并没有考虑目标SQL中所涉及的对象的实际数量,实际数据的分布情况,这样一旦规则不适用于该SQL,那么很可能选出来的执行计划就不是最优执行计划了。

  • CBO---Cost_Based Potimizer 基于成本的优化器:CBO在会从目标诸多的执行路径中选择一个成本最小的执行路径来作为执行计划。这里的成本他实际代表了MySQL根据相关统计信息计算出来目标SQL对应的步骤的IO,CPU等消耗。也就是意味着数据库里的成本实际上就是对于执行目标SQL所需要IO,CPU等资源的一个估计值。而成本值是根据索引,表,行的统计信息计算出来的(计算过程比较复杂)。

第五步执行器:开始执行的时候,首先会判断此次连接是否有对应的操作权限,如果没有,则返回没有权限的错误。如果有权限,则打开表继续执行。打开表的时候,执行器会根据表的引擎定义,去使用这个引擎提供的接口。

比如下面这条sql语句执行器流程是这样的:

select * from t_test3 where name = 'a';
  1. 调用InnoDB引擎接口获取这个表的第一行,判断name的值是不是a,如果不是则跳过,如果是则将这行存在结果集中。

  2. 调用引擎接口获取下一行,重复相应的判断逻辑,直到取到最后一行数据

  3. 执行器将遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

通过了解sql执行的过程以及优化器,发现mysql采用的是第二种基于成本的优化器,它会根据sql执行的成本选择合适的路径。所以可以推断出上面sql执行计划没有采用对应列的索引原因。当我在表中插入一万条数据的时候,再重新查看对应的执行计划时,发现此时,该sql的查询类型会使用range类型及使用name对应的索引进行查询。

当数据量比较小的时候,会使用all类型进行查询对应数据,当数据量比较大时,查询数据量增大时,会采用range类型,并使用对应列的索引进行查询。这便涉及到了数据库查询索引的离散度。 离散度,外文 Measures of Dispersion,是指通过随机地观测变量各个取值之间的差异程度,用来衡量风险大小的指标。离散度在不超过全表的10%-15%的前提下索引才可以显示索引所具有的价值。当离散度超过该值的情况下全表扫描可能反倒比索引扫描更有效。我们所追求的目标就是创建全表扫描所无法比拟的有效索引。  比如当我们对一张学生表信息中对性别添加索引,性别只有两种值,会产生大量的重复,离散度较小,使用性别索引会增加查询开销,使得在使用性别的索引查询时可能比没有性别索引的查询更慢。

基于数据库索引的离散度,可以参考以下两个建议进行创建索引:

  • 在允许的情况下,对具有较好离散度的列单独创建索引,这样可以提高该索引的使用弹性;

  • 对于离散度较差的列,通过对多列进行合理的组合来创建组合索引,虽然这样做在很大程度上降低了各个列的使用弹性,但是却可以发挥多个列的综合效应。

在实际应用的过程中,MySQL索引失效的情形很多。例如: 在WHERE条件的LIKE关键字匹配的字符串以”%“开头,这种情况下,索引是不会起到作用的;WHERE条件中使用OR关键字来连接多个查询条件,如果有一个条件没有使用索引,那么其他的索引也不会起作用;多列索引的第一个字段没有使用,那么这个多列索引也不会起作用。 使用in查询时,in查询条件超过数据库表的一半的时候也会失效。

根据这些情况,我们必须选择对索引有正确的理解,并不是创建索引就能增加查询速度。根据使用索引的特性,对创建索引的一些技巧总结如下:

  1. 首先数据量小的表不需要建立索引,因为数据量小的表即使建立索引也不会有大的用处,还会增加额外的索引开销 。

  2. 不经常引用的列不要建立索引,因为不常用,即使建立了索引也没有多大意义 。

  3. 经常频繁更新的列不要建立索引,因为肯定会影响插入或更新的效率 。

  4. 尽量避免在 where 子句中使用 != 或者 <> 操作符,查询引用会放弃索引而进行全表扫描。

  5. 数据类型越小越简单的索引更好。越小越简单的数据类型通常在磁盘、内存和cpu缓存中需要的空间更少,处理起来更快。

  6. 尽量避免NULL: 在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。可以采用0、一个特殊的值或者一个空串代替空值 。

在实际应用的过程中,mysql并不总会选择合理的索引进行查询,此时便可以使用force index(index name)来强制告诉mysql选择哪一个索引。使用一下sql查询:

desc select * from t_test3 force INDEX (t_test_name) where name in ('a','b');

其对应的执行计划与上图的执行计划相同,采用的是sql中指定的索引。

因此我们在一些情况下首先可以适当的使用force index(indexname) 强制告诉mysql使用什么索引。force index( index name )指令可以指定本次查询使用哪个索引!一条sql只会用到一个索引,mysql优化器会计算出一个合适的索引,但是这个索引不一定是最好的。force index()指令可以避免MySql优化器用到了一个低效的索引,并可以提高sql的执行效率。

【End】

CSDNx巨杉大学联合认证学习,免费开放!“分布式数据库集训营”帮助您从零开始学习分布式数据库、分布式架构知识,现在加入活动,完成课程还将专属礼品。快来参加吧~

推荐阅读 

☞阿里平头哥科学家亲述 RISC-V 2019 Summit 十大心得!

☞复制粘贴发明人、Java 和互联网创建者相继去世,向初代互联网大佬致敬!

☞夺得WSDM Cup 2020大赛金牌的这份参赛方案,速来get!

☞“不让一块芯片流向华为”?

☞稳定、可扩展、模块化、简化部署过程、版本控制……一文看懂 Kubernetes 到底如何运用!

☞耐克为何不接受加密货币付款?

你点的每一个在看,我认真当成了喜欢

猛戳“阅读原文”,了解详情!

面对 MySQL 查询索引失效,程序员的六大优化技巧!相关推荐

  1. mysql 子查询索引失效_mysql 索引失效的情况

    索引失效的几种情况 1.如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因) 要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引 2.对于多列索引,不是使用 ...

  2. 范围查找(比如日期范围)下查询出现全表扫描MySQL数据库索引失效

    范围查找(比如日期范围)下查询出现全表扫描MySQL数据库索引失效 当下MySQL数据库在多款数据库中脱颖而出,成为使用最广泛的数据库之一,这里我们来看看数据库索引上的一个问题.我们知道在数据量上去以 ...

  3. MySQL调优是程序员拿高薪的必备技能?

    前言 有一句很有意思的话:现在的世界,得数据者得天下. 可见数据对于我们.对于企业.对于未来发展来说都十分重要. 而想要"得天下",掌握海量数据,那么对存储.读写数据的数据库的要求 ...

  4. mysql in 索引 失效_in 索引失效的问题

    简单的in查询 索引失效: 步骤 1.检查建立索引没有 order_status 字段为普通索引的tinyint类型 2.检查是否使用了使索引失效的语句 3.explain查看执行计划 而 in(1) ...

  5. 【2022黑马程序员】SQL优化

    [黑马程序员]SQL优化笔记 文章目录 [黑马程序员]SQL优化笔记 插入数据优化 大批量插入数据 总结 主键优化 数据组织方式 页分裂 A. 主键顺序插入效果 B. 主键乱序插入效果 页合并 索引设 ...

  6. 师妹问我:有哪些新手程序员不知道的小技巧?

    阅读本文大概需要5分钟. 一个师妹问:洋哥,我今年应届毕业,刚开始写代码,不知道有没有一些新手需要注意的地方. 给了师妹一些建议之后,感觉这是个好问题!不光是新手程序员,很多小技巧小秘密恐怕老手也未必 ...

  7. 程序员装B小技巧——管理你的桌面

    程序员装B小技巧--管理你的桌面 引言 想不想拥有一个和下方截图一样简单快捷的桌面?随着工作学习的时间推移,我们电脑里面的各种软件和文档日渐增多,导致我们的桌面变得杂乱且不美观.身为一个程序员怎么能容 ...

  8. 给程序员的十条沟通技巧建议【奥利给】

    1.沟通的保障:及时反馈 工作方面:完成立马汇报,不能让领导催着或盯着你完成.完成一件事情需要很久时间则需进行阶段性汇报,工作中不要惊喜,只要安全感. 2.沟通的前提:正确的沟通基调 面试方面:地位平 ...

  9. 程序员必备的沟通技巧

    目录 程序员必备的沟通技巧 1. 及时反馈 2. 不要紧张 3. 诚信 4. 以友善的态度开始 5. 沟通的定义: 6. 沟通的方式 8. 性别差异 9. 语言障碍 10. 知识结构 沟通的技巧 1. ...

最新文章

  1. Linux学习4-文件系统介绍
  2. python 导入包的路径_关于Python包导入的知识点你知道吗?
  3. 矩阵快速幂各类题型总结(一般,共轭,1 * n, 矩阵简化)
  4. 【转】.net异步性能测试(包括ASP.NET MVC WebAPI异步方法)
  5. 新SQL Server 2016示例数据库
  6. easyui-treegrid的案例
  7. aspose word 删除空行_Word:删除空行
  8. Java 编码规范3(编程规约-代码格式)
  9. 超级搜索术3-吸收应用/一键直达
  10. 基于java的百货中心供应链管理系统
  11. 腾讯课堂后台扩容和性能优化实战
  12. 年轻人如何去有效的学习(很好的鸡汤,一语惊醒梦中人)
  13. 怎样学习AI-Adobe
  14. 安装python环境以及安装pycharm编译器教程
  15. 爬虫实战2(下):爬取豆瓣影评
  16. 学习C语言篇之网络编程操作
  17. 随机洗牌算法+matlab,洗牌算法及 random 中 shuffle 方法和 sample 方法浅析
  18. 品优购商城项目常见BUG解析
  19. JavaScript基础知识学习与刷题
  20. SQL语句 -非空约束 - 唯一约束 - 主键约束 - 默认约束 -外键约束

热门文章

  1. IDEA将maven项目配置到本地tomcat中运行
  2. Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件
  3. Javascript是实现HTML5强大功能的重要语言
  4. 文档开发工具调研总结
  5. Caffe100数据集使用
  6. [CMake] 简单的样例工程
  7. 碧蓝航线维护服务器时间,碧蓝航线3月21日维护时间更新公告 新增与更改内容介绍...
  8. 中国水密门市场趋势报告、技术动态创新及市场预测
  9. 中国塑料食品和饮料包装行业市场供需与战略研究报告
  10. 2021年中国一氧化碳传感器市场趋势报告、技术动态创新及2027年市场预测