前言

之前看了很多关于MySQL索引的文章也看了《高性能MySQL》这本书,自以为熟悉了MySQL索引使用原理,入职面试时和面试官交流,发现对复合索引的使用有些理解偏颇,发现自己的不足整理一下这方面的内容。

实例表:

CREATE TABLE `test` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uId` int(10) unsigned NOT NULL,
`chatId` smallint(5) unsigned NOT NULL,
`tId` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `test_uId_chatId_tId` (`uId`,`chatId`,`tId`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4;

最左前缀匹配原则

  在MySQL建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配,示例:

对列uId、列chatId和列tId建一个联合索引

shell KEY test_uId_chatId_tId on test(uId,chatId,tId);

联合索引test_uId_chatId_tId 实际建立了(uId)、(uId,chatId)、(uId,chatId,tId)三个索引。

SELECT * FROM test WHERE uId=“1” AND chatId=“2”;

上面这个查询语句执行时会依照最左前缀匹配原则,检索时会使用索引(uId,chatId)进行数据匹配。

注意:

索引的字段可以是任意顺序的,如:

SELECT * FROM test WHERE uId=“1” AND chatId=“2”;

SELECT * FROM test WHERE chatId=“2” AND uId=“1”;

这两个查询语句都会用到索引(uId,chatId),MySQL创建联合索引的规则是首先会对联合合索引的最左边的,也就是第一个字段uId的数据进行排序,在第一个字段的排序基础上,然后再对后面第二个字段chatId进行排序。其实就相当于实现了类似 order by uId chatId这样一种排序规则。

  有人会疑惑第二个查询语句不符合最左前缀匹配:首先可以肯定是两个查询语句都包涵索引(uId,chatId)中的uId、chatId两个字段,只是顺序不一样,查询条件一样,最后所查询的结果肯定是一样的。既然结果是一样的,到底以何种顺序的查询方式最好呢?此时我们可以借助mysql查询优化器explain,explain会纠正sql语句该以什么样的顺序执行效率最高,最后才生成真正的执行计划。

为什么要使用联合索引

  • 减少开销,联合索引test_uId_chatId_tId 实际建立了(uId)、(uId,chatId)、(uId,chatId,tId)三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大的减少开销!
  • 覆盖索引,对联合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。
  • 效率高,索引列越多,通过索引筛选出的数据越少。有1000W条数据的表,有如下sql:select from table where col1=1 and col2=2 and col3=3,假设假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W10%=100w条数据,然后再回表从100w条数据中找到符合col2=2 and col3= 3的数据,然后再排序,再分页;如果是联合索引,通过索引筛选出1000w10% 10% *10%=1w,效率提升可想而知!

    引申:

    对于联合索引(uId,chatId,tId),查询语句SELECT * FROM test WHERE chatId=2;是否能够触发索引,当时面试官问我时我回答是不触发,实际上是触发索引的

    原因总结:
EXPLAIN SELECT * FROM `test` WHERE uid='1' AND chatId='2';
EXPLAIN SELECT * FROM `test` WHERE chatId='2';

观察上述两个explain结果中的type字段。查询中分别是:

上述两个查询的explain结果中显示用到索引的情况类型是不一样的。可观察explain结果中的type字段,分别是:

  • type: index

    index:这种类型表示mysql会对整个该索引进行扫描。要想用到这种类型的索引,对这个索引并无特别要求,只要是索引,或者某个联合索引的一部分,mysql都可能会采用index类型的方式扫描。但是呢,缺点是效率不高,mysql会从索引中的第一个数据一个个的查找到最后一个数据,直到找到符合判断条件的某个索引。所以,上述语句会触发索引。
  • type: ref

    ref:这种类型表示mysql会根据特定的算法快速查找到某个符合条件的索引,而不是会对索引中每一个数据都进行一一的扫描判断,也就是所谓你平常理解的使用索引查询会更快的取出数据。而要想实现这种查找,索引却是有要求的,要实现这种能快速查找的算法,索引就要满足特定的数据结构。简单说,也就是索引字段的数据必须是有序的,才能实现这种类型的查找,才能利用到索引。

MySQL联合索引运用-最左匹配原则的更多相关文章

  1. Mysql中联合索引的最左匹配原则

    在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先. 如果我们建立了一个2列的联合索引(col1,col2),实际上已经建立了两个联合索引(col1).(col1,col2); 如果有一 ...

  2. Mysql中联合索引的最左匹配原则(百度)

    创建联合索引时列的选择原则 经常用的列优先(最左匹配原则) 离散度高的列优先(离散度高原则) 宽度小的列优先(最少空间原则) 在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先.如果我们 ...

  3. MySQL联合索引最左匹配范例

    MySQL联合索引最左匹配范例 参考文章:http://blog.jobbole.com/24006/ 创建示例表. 示例表来自MySQL官方文档: https://dev.mysql.com/doc ...

  4. 我说MySQL联合索引遵循最左前缀匹配原则,面试官让我回去等通知

    面试官: 我看你的简历上写着精通MySQL,问你个简单的问题,MySQL联合索引有什么特性? 心想,这还不简单,这不是问到我手心里了吗? 听我给你背一遍八股文! 我: MySQL联合索引遵循最左前缀匹 ...

  5. MySQL 联合索引详解

    MySQL 联合索引详解   联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分.例如索引是key index (a,b,c ...

  6. mysql 联合索引(转)

    http://blog.csdn.net/lmh12506/article/details/8879916 mysql 联合索引详解 联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中 ...

  7. [转]mysql联合索引

    mysql联合索引   命名规则:表名_字段名1.需要加索引的字段,要在where条件中2.数据量少的字段不需要加索引3.如果where条件中是OR关系,加索引不起作用4.符合最左原则 https:/ ...

  8. 三道MySQL联合索引面试题,淘汰80%的面试者,你能答对几道

    众所周知MySQL联合索引遵循最左前缀匹配原则,在少数情况下也会不遵循(有兴趣,可以翻一下上篇文章). 创建联合索引的时候,建议优先把区分度高的字段放在第一列. 至于怎么统计区分度,可以按照下面这种方 ...

  9. SQL Server中的联合主键、聚集索引、非聚集索引、mysql 联合索引

    我们都知道在一个表中当需要2列以上才能确定记录的唯一性的时候,就需要用到联合主键,当建立联合主键以后,在查询数据的时候性能就会有很大的提升,不过并不是对联合主键的任何列单独查询的时候性能都会提升,但我 ...

随机推荐

  1. 【转】Jmeter做功能测试的优点和不足

    利用Jmeter做功能测试有以下优点: ●    不依赖于界面,如果服务正常启动,传递参数明确就可以添加测试用例,执行测试 ●    测试脚本不需要编程,熟悉http请求,熟悉业务流程,就可以根据页面 ...

  2. 水仙花之java与c++的战争======

    总结:同样在C++里可以运行正常的水仙花,在java里不行 为什么??是运算符优先级的问题吗: package com.a; //水仙花数 一个三位数 324:426/195 public class ...

  3. xunsearch全文检索初体验

    目录 测试添加数据 测试搜索 简单搜索 稍微复杂的搜索 搜索建议 测试添加数据 ./Indexer.php --source=csv --clean demo 清空现有索引数据 ... 初始化数据源 ...

  4. babel-polyfill使用简介

    babel-polyfill介绍 简介 使用这个插件你可随心所欲的使用es6甚至更高版本的方法,这个插件自动转码 安装 这个插件必须在你的源码运行之前运行,所以必须安装成dependency npm ...

  5. 关闭PdfReader右侧工具栏的方法

    1.首先单次关闭工具栏 点击视图-显示/隐藏-工具窗格,关闭右侧工具栏,但下次打开pdf还会出来,所以: 2.记住设置状态 编辑-首选项-文档-记住工具窗格当前状态

  6. Java面向对象-static关键字、静态方法与普通方法、静态成员变量

    Java面向对象-static关键字.静态方法与普通方法 static关键字的基本作用:方便在没有创建对象的情况下来进行调用(方法/变量). 很显然,被static关键字修饰的方法或者变量不需要依赖于 ...

  7. leetcode905

    vector<int> sortArrayByParity(vector<int>& A) { vector<int> EVEN;//偶数 vector&l ...

  8. C++深度解析教程学习笔记(3)函数的扩展

    1.内联函数 1.1.常量与宏的回顾 (1)C++中的 const 常量可以替代宏常数定义,如: ; //等价于 #define A 3 (2)C++中是否有解决方案,可以用来替代宏代码片段呢? 1. ...

  9. A Look at the Razor View Engine in ASP.NET MVC

    The biggest architectural difference that exists between ASP.NET MVC and ASP.NET Web Forms is the ne ...

  10. SpringBoot15 sell01 项目创建、MySQL数据库连接、日志配置、开发热部署、商品信息模块

    项目软件版本说明: jdk: 1.8 springboot: 2.0.1 mysql: 5.7 1 项目创建 创建一个SpringBoot项目即可,创建是勾选 web jpa mysql 这三个依赖就 ...