MySQL联合索引运用-最左匹配原则
前言
之前看了很多关于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联合索引运用-最左匹配原则的更多相关文章
- Mysql中联合索引的最左匹配原则
在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先. 如果我们建立了一个2列的联合索引(col1,col2),实际上已经建立了两个联合索引(col1).(col1,col2); 如果有一 ...
- Mysql中联合索引的最左匹配原则(百度)
创建联合索引时列的选择原则 经常用的列优先(最左匹配原则) 离散度高的列优先(离散度高原则) 宽度小的列优先(最少空间原则) 在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先.如果我们 ...
- MySQL联合索引最左匹配范例
MySQL联合索引最左匹配范例 参考文章:http://blog.jobbole.com/24006/ 创建示例表. 示例表来自MySQL官方文档: https://dev.mysql.com/doc ...
- 我说MySQL联合索引遵循最左前缀匹配原则,面试官让我回去等通知
面试官: 我看你的简历上写着精通MySQL,问你个简单的问题,MySQL联合索引有什么特性? 心想,这还不简单,这不是问到我手心里了吗? 听我给你背一遍八股文! 我: MySQL联合索引遵循最左前缀匹 ...
- MySQL 联合索引详解
MySQL 联合索引详解 联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分.例如索引是key index (a,b,c ...
- mysql 联合索引(转)
http://blog.csdn.net/lmh12506/article/details/8879916 mysql 联合索引详解 联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中 ...
- [转]mysql联合索引
mysql联合索引 命名规则:表名_字段名1.需要加索引的字段,要在where条件中2.数据量少的字段不需要加索引3.如果where条件中是OR关系,加索引不起作用4.符合最左原则 https:/ ...
- 三道MySQL联合索引面试题,淘汰80%的面试者,你能答对几道
众所周知MySQL联合索引遵循最左前缀匹配原则,在少数情况下也会不遵循(有兴趣,可以翻一下上篇文章). 创建联合索引的时候,建议优先把区分度高的字段放在第一列. 至于怎么统计区分度,可以按照下面这种方 ...
- SQL Server中的联合主键、聚集索引、非聚集索引、mysql 联合索引
我们都知道在一个表中当需要2列以上才能确定记录的唯一性的时候,就需要用到联合主键,当建立联合主键以后,在查询数据的时候性能就会有很大的提升,不过并不是对联合主键的任何列单独查询的时候性能都会提升,但我 ...
随机推荐
- 【转】Jmeter压力测试模拟并发
jmeter下载地址:http://jmeter.apache.org/download_jmeter.cgi JMeterPlugins(jmeter插件):http://jmeter-plugin ...
- python开发mysql:视图、触发器、事务、存储过程、函数
一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 使用视图我们可以把查询过程中的 ...
- JavaScript笔记——BOM的操作和浏览器的检测
BOM的操作 BOM 也叫浏览器对象模型,它提供了很多对象,用于访问浏览器的功能.BOM 缺少规范,每个浏览器提供商又按照自己想法去扩展它,就可能存在浏览器不兼容的情况,那么浏览器共有对象就成了事实的 ...
- DFS leetcode
把字符串转换成整数 class Solution { public: int StrToInt(string str) { int n = str.size(), s = 1; long long r ...
- 自定义inputformat和outputformat
1. 自定义inputFormat 1.1 需求 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案 1.2 分析 小文件的优 ...
- html5调用本机摄像头兼容谷歌浏览器高版本,谷歌浏览器低版本,火狐浏览器
做这个功能的时候在网上查了一些资料,代码如下,在这个代码在谷歌浏览器46版本是没问题的,在火狐浏览器也行,但是在谷歌浏览器高版本下是不兼容的 <div id="body"&g ...
- linux多线程默认栈大小和最大线程数
linux的线程栈大小可以使用ulimit -s查看,对于ubunt 2.6的内核线程栈的默认大小为8M,如下: shine@shine-bupt:~/Program/C$ ulimit -s 819 ...
- Scala中的函数
Scala中的函数 提纲 1.Scala中的函数简介 2.Scala中的函数的各种写法 1.Scala中的函数简介 =================== Scala是函数式编程和面向对象式编程的混合 ...
- MFC小程序
1.将菜单栏归零,工具栏放在窗口低部,加载自己新建的工具栏 CMainFrame::OnCreate()函数中 this->SetMenu(0); 2.将窗口初始化为最大化 APP类中:m_pM ...
- Collision Detection
[Collision Detection] Collision Detection是Rigidbody中的一个属性.所以显然Collision Detection指定的类型只在Rigidbody之间才 ...