本文为博主原创,未经允许不得转载:

  我们都知道创建索引的目的是快速从整体集合中选择性地读取满足条件的一部分集合。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%的前提下索引才可以显示索引所具有的价值。当离散度超过该值的情况下全表扫描可能反倒比索引扫描更有效。我们所追求的目标就是创建全表扫描所无法比拟的有效索引。 比如当我们对一张学生表信息中对性别添加索引,性别只有两种值,会产生大量的重复,离散度较小,使用性别索引会增加查询开销,使得在使用性别的索引查询时可能比没有性别索引的查询更慢。

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

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

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

在实际应用的过程中,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的执行效率。

MySQL 查询索引失效及如何进行索引优化的更多相关文章

  1. mysql索引失效原理(联合索引失效问题)

    单值索引B+树图单值索引在B+树的结构里,一个节点只存一个键值对 联合索引开局一张图,由数据库的a字段和b字段组成一个联合索引. 从本质上来说,联合索引也是一个B+树,和单值索引不同的是,联合索引的键 ...

  2. mysql查询INFORMATION_SCHEMA表很慢的性能优化

    最近发现,我们有些环境的tomcat应用启动非常缓慢,大部分在3-5分钟,有个测试环境更加阶段,要十几分钟才能启动完成.经过仔细分析,是一个查询INFORMATION_SCHEMA库中数据字典信息的查 ...

  3. MySQL 索引失效-模糊查询,最左匹配原则,OR条件等。

    索引失效 介绍 索引失效就是我们明明在查询时的条件为索引列(包括自己新建的索引),但是索引不能起效,走的是全表扫描.explain 后可查看type=ALL. 这是为什么呢? 首先介绍有以下几种情况索 ...

  4. SQL优化 MySQL版 - 避免索引失效原则(一)

    避免索引失效原则(一) 精力有限,剩余的失效原则将会在 <避免索引失效原则(二)>中连载出来,请谅解 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 避免索引失效的一些原 ...

  5. MySQL索引失效及使用索引的优缺点

    本文所有实验基于MySQL5.7.21,实验将会用到Explain工具,不了解的同学可参考此文章:MySQL性能优化神器Explain详解 联合索引失效 先创建一个包含三个字段的联合索引,索引顺序如下 ...

  6. MySQL优化之避免索引失效的方法

    在上一篇文章中,通过分析执行计划的字段说明,大体说了一下索引优化过程中的一些注意点,那么如何才能避免索引失效呢?本篇文章将来讨论这个问题. 避免索引失效的常见方法 1.对于复合索引的使用,应按照索引建 ...

  7. 《MySQL面试小抄》索引失效场景验证

    我是肥哥,一名不专业的面试官! 我是囧囧,一名积极找工作的小菜鸟! 囧囧表示:小白面试最怕的就是面试官问的知识点太笼统,自己无法快速定位到关键问题点!!! 本期主要面试考点 面试官考点之什么情况下会索 ...

  8. MySQL索引失效之隐式转换

    常见索引失效: 1. 条件索引字段"不干净":函数操作.运算操作 2. 隐式类型转换:字符串转数值:其他类型转换 3. 隐式字符编码转换:按字符编码数据长度大的方向转换,避免数据截 ...

  9. 面试突击60:什么情况会导致 MySQL 索引失效?

    为了验证 MySQL 中哪些情况下会导致索引失效,我们可以借助 explain 执行计划来分析索引失效的具体场景. explain 使用如下,只需要在查询的 SQL 前面添加上 explain 关键字 ...

  10. 「MySQL高级篇」explain分析SQL,索引失效&&常见优化场景

    大家好,我是melo,一名大三后台练习生 专栏回顾 索引的原理&&设计原则 欢迎关注本专栏:MySQL高级篇 本篇速览 在我们上一篇文章中,讲到了索引的原理&&设计原则 ...

随机推荐

  1. 【scikit-learn基础】--『预处理』之 正则化

    数据的预处理是数据分析,或者机器学习训练前的重要步骤.通过数据预处理,可以 提高数据质量,处理数据的缺失值.异常值和重复值等问题,增加数据的准确性和可靠性 整合不同数据,数据的来源和结构可能多种多样, ...

  2. 袋鼠云数栈UI5.0设计实战|B端表单这样设计,不仅美观还提效

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:大喜 相关文章:袋鼠云出品!数栈UI 5.0全新体验升级, ...

  3. flex布局之美,以后就靠它来布局了

    写在前面 在很久很久以前,网页布局基本上通过table 元素来实现.通过操作table 中单元格的align 和valign可以实现水平垂直居中等 再后来,由于CSS 不断完善,便演变出了:标准文档流 ...

  4. 数仓调优实践丨SQL改写消除相关子查询

    本文分享自华为云社区<[调优实践]SQL改写消除相关子查询>,作者: 门前一棵葡萄树 . 一.子查询 GaussDB(DWS)根据子查询在SQL语句中的位置把子查询分成了子查询.子链接两种 ...

  5. RT-DETR:可以满足实时性要求的DETR模型

    本文分享自华为云社区<高性能网络设计秘笈:深入剖析Linux网络IO与epoll>,作者: Lion Long . 一.epoll简介 epoll是Linux内核中一种可扩展的IO事件处理 ...

  6. 8种桌面IDE CodeArts智能代码补全类型

    摘要:代码补全可以有效的提升开发效率.减少拼写错误和输入代码量.CodeArts 依赖于 codearts.smartassist-java-ls 插件实现代码补全功能. 本文分享自华为云社区< ...

  7. maven中引入CDH依赖包,Cannot resolve org.apache.hadoop:hadoop-hdfs:3.0.0-cdh6.3.2

    POM文件加入仓库 cloudera https://repository.cloudera.com/artifactory/cloudera-repos/ 修改MAVEN配置文件 nexus-ali ...

  8. iOS应用程序发布流程:从测试到上架的完整指南

    ​ 目录 转载:iOS应用程序的签名.重签名和安装测试 前言 打开要处理的IPA文件 设置签名使用的证书和描述文件 开始ios ipa重签名 转载:iOS应用程序的签名.重签名和安装测试 前言 ipa ...

  9. 十大 CI/CD 安全风险(五)

    在本篇文章中,我们将了解第三方服务的监管不足,工件完整性验证及日志可见性不足这三个关键 CI/CD 安全风险,并给出缓解相应风险的建议与措施. 第三方服务监管不足 CI/CD 攻击面包括企业资产,例如 ...

  10. 抖音"凶猛"的幕后英雄,火山引擎 DataTester 累计做过 150 万次 A/B 测试

    在国内互联网领域,字节跳动是最为推崇 A/B 测试的公司,旗下"抖音"."今日头条"两大最著名产品,连 APP 的名字都是来源于 A/B 测试. A/B 测试( ...