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中 ...
随机推荐
- tar 加密压缩和解密解压
加密压缩 tar -czvf - file | openssl des3 -salt -k password -out /path/to/file.tar.gz 解密解压 openssl des3 - ...
- 【bzoj3488】[ONTAK2010]Highways DFS序+树上倍增+树状数组
题目描述 一棵n个点的树,给定m条路径,q次询问包含一条路径的给定路径的个数+1 输入 The first line of input contains a single integer N(1< ...
- ASP.NET页面之间传值QueryString(1)
QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中.如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法.但是对于传递数组或对象的话,就不能用这 ...
- 机器学习模型-支持向量机(SVM)
二.代码实现 import numpy as np from sklearn import datasets from sklearn.model_selection import train_tes ...
- BZOJ4568 [Scoi2016]幸运数字 【点分治 + 线性基】
题目链接 BZOJ4568 题解 选任意个数异或和最大,使用线性基 线性基插入\(O(logn)\),合并\(O(log^2n)\) 我们要求树上两点间异或和最大值,由于合并是\(O(log^2n)\ ...
- 如何用JavaScript做一个可拖动的div层
可拖动的层在Web设计中用处很多,比如在某些需要自定义风格布局的应用中,控件就需要拖动操作,下面介绍一个,希望可以满足你的需求,顺便学习一下可拖动的层是如何实现的. 下面是效果演示: 这个DIV可以移 ...
- Codeforces Round #525 (Div. 2) F. Ehab and a weird weight formula
F. Ehab and a weird weight formula 题目链接:https://codeforces.com/contest/1088/problem/F 题意: 给出一颗点有权值的树 ...
- typescript的入门
命令行使用tsc 1.安装typescript npm install -g typescript 2.新建一个index.ts 输入export hello class{} 3.编译 tsc ind ...
- spring 中的@Import注解和@ImportResource注解
概述:@Import注解是引入带有@Configuration的java类. @ImportResource是引入spring配置文件.xml 案例的核心代码如下: package com.timo. ...
- 解决“并非来自 Chrome 网上应用店。”
Chrome谷歌浏览器已停用不支持的扩展程序解决方法 第一种方法:(亲测有效) 1.首先把需要安装的第三方插件,后缀.crx 改成 .rar,然后解压,得到一个文件夹 2.再打开chrome://ex ...