下面分别创建三张表,并分别插入1W条简单的数据用来测试,详情如下:
[1] test_a 有主键但无索引
CREATE TABLE `test_a` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`content` text NOT NULL,
`number` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
[2] test_b 有主键和单列索引
CREATE TABLE `test_b` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`content` text NOT NULL,
`number` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `titleIndex` (`title`) USING BTREE,
UNIQUE KEY `numberIndex` (`number`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
[3] test_c 有主键和组合索引
CREATE TABLE `test_c` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`content` text NOT NULL,
`number` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `titleNumberIndex` (`title`,`number`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
下面按照单列索引和组合索引分别对以上三张表进行查询测试,另外下面的时间都是多次测试取的平均值。
[1] 单列索引
[1.1] 查询指定的字段
[SQL] SELECT * FROM test_a WHERE title = 'title_5000';
[USE] 12ms
[SQL] SELECT * FROM test_b WHERE title = 'title_5000';
[USE] <1ms
说明:可以看到未加索引时间为12ms,加索引后小于1ms,还是相差很大的。
[SQL] SELECT * FROM test_a WHERE content = 'content_5000';
[USE] 13ms
[SQL] SELECT * FROM test_b WHERE content = 'content_5000';
[USE] 13ms
说明:由于content字段都未加索引,因此时间基本一致。
[1.2] 测试LIKE查询
[SQL] SELECT * FROM test_a WHERE title LIKE '%5000';
[USE] 13ms
[SQL] SELECT * FROM test_b WHERE title LIKE '%5000';
[USE] 13ms
说明:两者用时基本一致,因此索引并未命中。
[SQL] SELECT * FROM test_a WHERE title LIKE '5000%';
[USE] 12ms
[SQL] SELECT * FROM test_b WHERE title LIKE '5000%';
[USE] <1ms
说明:如果LIKE是前缀匹配则会命中索引,否则不会命中。另外以上的查询结果为空,但是不影响说明索引的作用。
[1.3] 测试OR语句
[SQL] SELECT * FROM test_a WHERE title = 'title_5000' OR content = 'content_5000';
[USE] 13ms
[SQL] SELECT * FROM test_b WHERE title = 'title_5000' OR content = 'content_5000';
[USE] 13ms
说明:两者用时基本一致,因此索引并未命中。
[SQL] SELECT * FROM test_a WHERE title = 'title_5000' OR number = '5000';
[USE] 13ms
[SQL] SELECT * FROM test_b WHERE title = 'title_5000' OR number = '5000';
[USE] <1ms
说明:如果OR两边的字段都加索引则命中,否则只有一个加索引则不命中。
[1.4] 测试IN语句
[SQL] SELECT * FROM test_a WHERE title IN('title_4999','title_5000','title_5001');
[USE] 12ms
[SQL] SELECT * FROM test_b WHERE title IN('title_4999','title_5000','title_5001');
[USE] <1ms
说明:IN语句也是可以命中索引的。
[1.5] 测试(BETWEEN,>,>=,<,<=)语句
[SQL] SELECT * FROM test_a WHERE number <= 5000;
[USE] 14ms
[SQL] SELECT * FROM test_b WHERE number <= 5000;
[USE] 14ms
[SQL] SELECT * FROM test_a WHERE number < 5000;
[USE] 14ms
[SQL] SELECT * FROM test_b WHERE number < 5000;
[USE] 14ms
[SQL] SELECT * FROM test_a WHERE number > 5000;
[USE] 14ms
[SQL] SELECT * FROM test_b WHERE number > 5000;
[USE] 14ms
[SQL] SELECT * FROM test_a WHERE number >= 5000;
[USE] 14ms
[SQL] SELECT * FROM test_b WHERE number >= 5000;
[USE] 14ms
[SQL] SELECT * FROM test_b FORCE INDEX(numberIndex) WHERE number >= 5000;
[USE] 14ms
[SQL] SELECT * FROM test_a WHERE number BETWEEN 4999 AND 5001;
[USE] 11ms
[SQL] SELECT * FROM test_b WHERE number BETWEEN 4999 AND 5001;
[USE] <1ms
说明:BETWEEN可以命中索引,其他比较符号未命中索引,强制使用索引效果也不明显,这个应该是与MySQL的索引足够性判断,如果索引大于30%就会使用全表扫描,具体待我查证后再详细介绍。
[1.6] 字段使用函数
[SQL] SELECT * FROM test_a WHERE SUBSTR(title,7,4) = '5000';
[USE] 13ms
[SQL] SELECT * FROM test_b WHERE SUBSTR(title,7,4) = '5000';
[USE] 13ms
说明:对字段使用函数则不能命中索引。
[2] 组合索引
[2.1] 测试OR语句
[SQL] SELECT * FROM test_a WHERE title = 'title_5000' OR content = 'content_5000';
[USE] 13ms
[SQL] SELECT * FROM test_c WHERE title = 'title_5000' OR content = 'content_5000';
[USE] 13ms
说明:组合索引中的OR语句没有命中索引。
[2.2] 测试AND语句
[SQL] SELECT * FROM test_a WHERE title = 'title_5000' AND number = 5000;
[USE] 12ms
[SQL] SELECT * FROM test_c WHERE title = 'title_5000' AND number = 5000;
[USE] <1ms
[SQL] SELECT * FROM test_a WHERE number = 5000;
[USE] 12ms
[SQL] SELECT * FROM test_c WHERE number = 5000;
[USE] 12ms
[SQL] SELECT * FROM test_a WHERE title = 'title_5000';
[USE] 12ms
[SQL] SELECT * FROM test_c WHERE title = 'title_5000';
[USE] <1ms
说明:以上证明了最左前缀匹配原则。
MySQL中EXPLAIN解释命令
EXPLAIN命令显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。
使用方法,在select语句前加上explain就可以了,如:
1
explain select surname,first_name form a,b where a.id=b.id
EXPLAIN列的解释:
table:显示这一行的数据是关于哪张表的
type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL
possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
key:实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
rows:MYSQL认为必须检查的用来返回请求数据的行数
Extra:关于MYSQL如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢
extra列返回的描述的意义
Distinct:一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
Not exists: MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了
Range checked for each Record(index map:#):没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort: 看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行
Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候
Using temporary 看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上
Where used 使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题不同连接类型的解释(按照效率高低的顺序排序)
system 表只有一行:system表。这是const连接类型的特殊情况
const:表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待
eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用
ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好
range:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况
index: 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)
ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免
- MySql 索引优化实例
查询语句 SELECT customer_id,title,content FROM `product_comment` WHERE audit_status=1 AND product_id=199 ...
- mysql sql优化实例
mysql sql优化实例 优化前: pt-query-degist分析结果: # Query 3: 0.00 QPS, 0.00x concurrency, ID 0xDC6E62FA021C85B ...
- mysql索引优化
mysql 索引优化 >mysql一次查询只能使用一个索引.如果要对多个字段使用索引,建立复合索引. >越小的数据类型通常更好:越小的数据类型通常在磁盘.内存和CPU缓存中都需要更少的空间 ...
- Mysql 索引优化分析
MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字 ...
- 知识点:Mysql 索引优化实战(3)
知识点:Mysql 索引原理完全手册(1) 知识点:Mysql 索引原理完全手册(2) 知识点:Mysql 索引优化实战(3) 知识点:Mysql 数据库索引优化实战(4) 索引原理知识回顾 索引的性 ...
- MySQL索引优化步骤总结
在项目使用mysql过程中,随着系统的运行,发现一些慢查询,在这里总结一下mysql索引优化步骤 1.开发过程优化 开发过程中对业务表中查询sql分析sql执行计划(尤其是业务流水表),主要是查看sq ...
- MySQL索引优化看这篇文章就够了!
阅读本文大概需要 5 分钟. 来源:cnblogs.com/songwenjie/p/9410009.html 本文主要讨论MySQL索引的部分知识.将会从MySQL索引基础.索引优化实战和数据库索引 ...
- mysql索引优化比普通查询速度快多少
mysql索引优化比普通查询速度快多少 一.总结 一句话总结:普通查询全表查询,速度较慢,索引优化的话拿空间换时间,一针见血,所以速度要快很多. 索引优化快很多 空间换时间 1.软件层面优化数据库查询 ...
- mySql索引优化分析
MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字 ...
随机推荐
- 阿里云服务器(Windows)如何下载文件
背景:公司只有我一个技术,在我之前还有一个老技术,属于兼职状态,为了尽快熟悉公司网站及app项目情况,我联系了老技术,请他尽快将代码发给我,他说代码文件过大,问我能不能连上服务器下载.百度了很多,都不 ...
- 关于Eclipse启动报错,jvm版本不匹配的问题
前几天重新下了个eclipse,eclipse需要java环境才能运行起来,我当时电脑上自己装了jdk1.8,然后直接运行新下载的eclipse,说我的jvm版本是1.6,但是我不记得安装过1.6的了 ...
- mapper.xml是怎样实现Dao层接口
上午写了一个简单的 从xml读取信息实例化一个Bean对象.下午就开始想mybatis是怎么通过xml文件来实现dao层接口的,一开始想直接用Class.forName(String name)然后调 ...
- 使用javaconfig配置freemarker
package com.yy.config; import org.springframework.context.annotation.Bean; import org.springframewor ...
- 启动tomcat错误:Address already in use: JVM_Bind:8081
解决方法: 1.打开任务管理器,关闭掉javaw进程. 2.修改tomcat端口:tomcat/conf/server.xml
- 归并排序Java实现
package practice; import edu.princeton.cs.algs4.*; /* * 归并排序 * 时间复杂度O(NlgN) N为数组长度 * 归并排序在小数组上表现并不好可 ...
- cobbler实现自动安装
author:JevonWei 版权声明:原创作品 cobbler 配置目录 配置文件目录 /etc/cobbler /etc/cobbler/settings : cobbler 主配置文件 /et ...
- 富文本编辑器UEditor的配置使用方法
将下载的富文本编辑器的文件解压后放到 webcontent 下 如果 文件中的jsp文件夹下的controller.java文件报错的话 就将jsp下的lib文件夹中的文件都复制到 web-i ...
- mac 终端常用目录跳转命令
以前一直都是使用Windows系统,连命令行都没怎么用过.来到了Mac,在某位大神的诱导下,我开始尝试使用Mac Terminal,下面总结的是一些简单的目录跳转命令 (菜鸟级) . 文件目录 首 ...
- select选择框在谷歌火狐和IE样式的不同
select选择在不同浏览器不同的显示样式, 在IE中 虽然默认和谷歌一样,但是当点击时向下 按钮消失, 解决方法如下: select { /*Chrome和Firefox里面的边框是不一样的,所以复 ...