MySQL 多列索引优化小记
MySQL 5.6.30
问题背景
由于爬虫抓取的数据不断增多,这两天在不断对数据库以及查询语句进行优化,其中一个表结构如下:
CREATE TABLE `newspaper_article` (
`id` varchar(50) NOT NULL COMMENT '编号',
`title` varchar(190) NOT NULL COMMENT '标题',
`author` varchar(255) DEFAULT NULL COMMENT '作者',
`date` date NULL DEFAULT NULL COMMENT '发表时间',
`content` longtext COMMENT '正文',
`status` tinyint(4) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idx_status_date` (`status`,`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';
根据业务需要,添加了 idx_status_date
索引,在执行下面这个 SQL 时特别耗时:
SELECT id, title, status, date FROM article WHERE status > -2 AND date = '2016-01-07';
根据观察,每天新增的数据大概在2500条以内,本以为这里指定了具体某天的日期 '2016-01-07'
,实际需要扫描的数据量应该在2500条以内才对,但实际并非如此:
实际共扫描了185589条数据,远远高于预估的2500条,且实际执行时间都将近3秒钟:
这是为什么呢?
解决方案
将 idx_status_date (status, date)
改为 idx_status (status)
后,查看 MySQL 执行计划:
可以看到将多列索引改为单列索引后,执行计划要扫描的数据总量没有任何变化。结合多列索引遵循最左前缀原则,推测上面的查询语句只使用了 idx_status_date
最左边的 status
的索引。
翻了下《高性能MySQL》找到了下面这段话,证实了我的想法:
如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。例如有查询
WHERE last_name = 'Smith' AND first_name LIKE 'J%' AND dob = '1976-12-23'
,这个查询只能使用索引的前两列,因为这里LIKE
是一个范围条件(但是服务器可以把其余列用于其他目的)。如果范围查询列值的数量有限,那么可以通过使用多个等于条件来代替范围条件。
因此,这里解决思路有两种:
- 可以通过使用多个等于条件来代替范围条件
- 修改
idx_status_date (status, date)
为索引idx_date_status (date, status)
,并新建一个idx_status
索引,即可达到同样的效果。
优化后的执行计划:
实际执行结果:
总结
当人们谈论索引的时候,如果没有特别指明类型,那么多半说的是 B-Tree
索引,它使用 B-Tree
数据结构来存储数据。我们使用术语“B-Tree”,是因为 MySQL 在 CREATE TABLE
和其他语句中也使用该关键字。不过,底层的存储引擎也可能使用不同的存储结构。InnoDB使用的是B+Tree。
假如有如下数据表:
CREATE TABLE People (
last_name varchar(50) not null,
first_name varchar(50) not null,
dob date not null,
gender enum('m', 'f') not null,
key(last_name, first_name, dob)
);
B-Tree 索引对如下类型的查询有效
- 全值匹配
全值匹配指的是和索引中的所有列进行匹配,例如上表的索引可用于查找姓名为 Cuba Allen 、出生于 1960-01-01 的人。 - 匹配最左前缀
上表中的索引可用于查找所有姓为 Allen 的人,即只使用索引的第一列。 - 匹配列前缀
只匹配某一列的值的开头部分。例如上表的索引可用于查找所有以 J 开头的姓的人。这里也只使用了索引的第一列。 - 匹配范围值
例如上表中的索引可用于查找姓在 Allen 和 Barrymore 之间的人。这里也只使用了索引的第一列。 - 精确匹配某一列并范围匹配另外一列
上表的索引也可用于查找所有姓为 Allen ,并且名字是字母 K 开头(比如 Kim 、 Karl 等)的人。即第一列 last_name 全匹配,第二列 first_name 范围匹配。 - 只访问索引的查询
B-Tree 通常可以支持“只访问索引的查询”,即查询只需要访问索引,而无须访问数据行。
B-Tree 索引的一些限制
- 如果不是按照索引的最左列开始查找,则无法使用索引。例如上表的索引无法用于查找名字为 Bill 的人,也无法查找某个特定生日的人,因为这两列都不是最左数据列。类似地,也无法查找姓氏以某个字母结尾的人。
- 不能跳过索引中列。也就是说,上表的索引无法用于查找姓氏为 Smith 并且在某个特定日期出生的人。如果不指定名(first_name),则 MySQL 只能使用索引的第一列。
- 如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查找。例如有查询
WHERE last_name = 'Smith' AND first_name LIKE 'J%' AND dob = '1976-12-23'
,这个查询只能使用索引的前两列,因为这里LIKE
是一个范围条件(但是服务器可以把其余列用于其他目的)。如果范围查询列值的数量有限,那么可以通过使用多个等于条件来代替范围条件。
原文链接:http://xueliang.org/article/detail/20170326235631083
MySQL 多列索引优化小记的更多相关文章
- mysql多列索引优化
“把Where条件里面的列都建上索引”,这种说法其实是非常错误的! 这样一个查询,假设actor_id与film_id都单独建立索引 SELECT film_id , actor_id FROM sa ...
- mysql多列索引和最左前缀
数据库的索引可以加快查询速度,原因是索引使用特定的数据结构(B-Tree)对特定的列额外组织存放,加快存储引擎(索引是存储引擎实现)查找记录的速度.索引优化是数据库优化的最重要手段. 如果查询语句使用 ...
- MySQL中的索引优化
MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 过多的使用索引将会造成滥用.因此索引也会有它的缺点.虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 ...
- MySql在建立索引优化时需要注意的问题
MySql在建立索引优化时需要注意的问题 设计好MySql的索引可以让你的数据库飞起来,大大的提高数据库效率.设计MySql索引的时候有一下几点注意: 1,创建索引 对于查询占主要的应用来说,索引显得 ...
- mysql数据库添加索引优化查询效率
项目中如果表中的数据过多的话,会影响查询的效率,那么我们需要想办法优化查询,通常添加索引就是我们的选择之一: 1.添加PRIMARY KEY(主键索引) mysql>ALTER TABLE `t ...
- mysql 多列索引的生效规则
mysql中 myisam,innodb默认使用的是 Btree索引,至于btree的数据结构是怎样的都不重要,只需要知道结果,既然是索引那这个数据结构最后是排好序:就像新华字典他的目录就是按照a,b ...
- MySQL系列(六)--索引优化
在进行数据库查询的时候,索引是非常重要的,当然前提是达到一定的数据量.索引就像字典一样,通过偏旁部首来快速定位,而不是一页页 的慢慢找. 索引依赖存储引擎层实现,所以支持的索引类型和存储引擎相关,同一 ...
- 【MySQL 高级】索引优化分析
MySQL高级 索引优化分析 SQL 的效率问题 出现性能下降,SQL 执行慢,执行时间长,等待时间长等情况,可能的原因有: 查询语句写的不好 索引失效 单值索引:在 user 表中给 name 属性 ...
- mysql 高级和 索引优化,目的:查的好,查的快,性能好
1-事物隔离级别: 更新丢失, 并发情况下,对同一字段进行更新,就会出现更新丢失,采用乐观锁,比较版本号或时间戳可解决 读未提交 解决了更新丢失但是会引起脏读, 二个session.sessionA中 ...
随机推荐
- Linux SPI总线和设备驱动架构之一:系统概述
SPI是"Serial Peripheral Interface" 的缩写,是一种四线制的同步串行通信接口,用来连接微控制器.传感器.存储设备,SPI设备分为主设备和从设备两种,用 ...
- 搭建Hadoop环境(一)
我用SecureCRT作为客户端,链接虚拟机做的服务器,我用的桥接,所以把主机的一个端口映射到虚拟机22端口上去,
- SRM708 div1 PalindromicSubseq(动态规划+容斥原理)
题目大意:给定一个字符串,记X[i]为包含s[i]这个字符的所有子列是回文串的个数(注意是子列而不是子串),求出所有的X[i]*(i+1),然后异或起来作为返回结果 题解: 首先用容斥来想,如果当前枚 ...
- hbase(0.94) get、scan源码分析
简介 本文是需要用到hbase timestamp性质时研究源码所写.内容有一定侧重.且个人理解不算深入,如有错误请不吝指出. 如何看源码 hbase依赖很重,没有独立的client包.所以目前如果在 ...
- MD5算法解析
MD5的全称是Message-Digest Algorithm 5,在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明,经MD2.MD3和MD4发展而来. MD5将 ...
- BZOJ4568 [Scoi2016]幸运数字 【点分治 + 线性基】
题目链接 BZOJ4568 题解 选任意个数异或和最大,使用线性基 线性基插入\(O(logn)\),合并\(O(log^2n)\) 我们要求树上两点间异或和最大值,由于合并是\(O(log^2n)\ ...
- 前端部署: nginx配置
前提:nginx 已安装 简介:nginx(engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Ram ...
- mpvue基本使用
## 什么是mpvue ## - 美团开发使用vue语法开发小程序的前端框架 - 适用于vue语法开发 - 会调用部分小程序API ## 创建mpvue项目 ## 1. 必须安装node.js 2. ...
- [BZOJ2946] [Poi2000]公共串解题报告|后缀数组
给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 单词个数<=5,每个单词长度<=2000 尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA... (其实是不 ...
- [Codevs1519]过路费解题报告|最小生成树|LCA
在某个遥远的国家里,有 n个城市.编号为 1,2,3,…,n.这个国家的政府修建了m 条双向道路,每条道路连接着两个城市.政府规定从城市 S 到城市T需要收取的过路费为所经过城市之间道路长度的最大值. ...