博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mysql:索引实战
阅读量:7059 次
发布时间:2019-06-28

本文共 2386 字,大约阅读时间需要 7 分钟。

 

MySQL主要提供2种方式的索引:B-Tree索引,Hash索引

B树索引具有范围查找和前缀查找的能力,对于有N节点的B树,检索一条记录的复杂度为O(LogN)。相当于二分查找。

哈希索引只能做等于查找,但是无论多大的Hash表,查找复杂度都是O(1)。

显然,如果值的差异性大,并且以等值查找(=、 <、>、in)为主,Hash索引是更高效的选择,它有O(1)的查找复杂度。

如果值的差异性相对较差,并且以范围查找(between and)为主,B树是更好的选择,它支持范围查找。

索引

无论是面试,还是实际工作中,对于一个Java程序员来说,数据库优化是避不开的一个技术点,关于数据库的优化,在性能达不到要求的情况下,我大致给出以下几个方向:

(1)优化表结构,对常用字段和非常用的字段分开存储

(2)优化SQL,合理使用索引

(3)做数据库读写分离,减少IO压力,由于数据库对记录做了持久化并存储在磁盘上,对磁盘的I/O又是非常消耗性能的操作,因此读、写都在一个库中会大大增加I/O的压力

(4)尝试使用缓存,不要让数据都走数据库

(5)对业务做垂直拆分

(6)对表做水平拆分,这一步比较麻烦,要注意主键生成规则以及请求路由规则

以上6个点是有优先级的,本文关注的是第二点的索引部分。正确合理地使用索引对于数据库性能提升是至关重要的,本文暂时不分析索引原理,只是从实战的角度,总结一下索引的使用技巧,理论结合实践,印象会更深一些。

当然,事前我已经建立了一张很简单的student表并向表中插入了10万条数据,SQL为:

DROP TABLE IF EXISTS `student`;CREATE TABLE `student` (  `s_id` int(11) NOT NULL AUTO_INCREMENT,  `s_name` varchar(100) DEFAULT NULL,  `s_age` int(11) DEFAULT NULL,  `s_phone` varchar(30) DEFAULT NULL,  PRIMARY KEY (`s_id`),  KEY `s_name` (`s_name`)) ENGINE=InnoDB, CHARSET=utf8;

 

使用普通索引与不使用普通索引的区别

先看一下不使用普通索引,进行查询,执行SQL语句:

select * from student where s_name = "99999ssss";

看一下查询时间:

花费了0.179秒,使用explain查看一下该条SQL语句的执行情况:

分析几个关键信息:

  • select_type:SIMPLE,这个不是很关键,只是表示这是一次简单的查询,没有join,没有union,没有中间表
  • type:ALL,表示该次SQL进行了全表查询
  • key:MySQL使用的索引名,这里null表示此次SQL查询MySQL并没有使用索引
  • rows:这个是最关键的,表示这次SQL查询了100665条记录

OK,接下来给s_name这一列加上普通索引:

alter table student add index s_name(s_name);

看一下运行结果:

看到在s_name上加上索引之后,查询速度马上快了3倍以上。

从分析结果上来看,由于此次SQL对列s_name使用了索引,因此rows只查了1条记录,大大提升了查询效率。

 

把索引建立在有大量重复数据的字段上

把索引建立在有大量重复数据的字段上,并不能有效地提升SQL效率,比如我的s_phone的取值为"00000000"~"99999999",此时对s_phone做查询,未加索引的时候:

看到这条select语句的查询时间是0.05秒,而给s_phone字段加了索引之后:

反而变为了0.064秒,并没有显著地提升查询效率,反而更加缓慢。通过explain语句,发现此次SQL通过索引查询了18000条rows,再去定位这18000多条数据,自然会慢一点。

这说明了,即使查询的时候用到了索引,也未必能提升查询的效率,索引建立在重复数据量很少的字段上效果才明显,但是这也将导致索引的增大,不过大多数时候这并不是太大的问题。

 

索引与like

不建议对索引列使用like语句,比如说执行以下两句SQL:

select * from student where s_name like "%99999ssss%";select * from student where s_name like "%99999ssss";

看一下explain出来的结果,都是一样的:

发现没有用到索引,这是对索引列使用like的限制,要对索引列使用like,通配符只能在结尾,开头不可以有任何的通配符,比如:

select * from student where s_name like "99999ssss%";

此时再explain看一下:

看到这么实用like则使用到了索引,这不得不说是一个限制。

 

索引与函数

在索引列上使用MySQL函数也会导致索引失效,看一个例子:

select * from student where "99999ssss" = left(s_name, 9);

这条SQL语句非常好理解,查询s_name列中从左边开始截取9个字符后的字符串为"99999ssss"的记录,查看一下explain的结果:

结果很明显,没有用到索引,这表明对索引列使用函数将导致索引失效。

一个技巧是,依然使用=,但是索引列不使用函数而对常数项使用函数,这样索引就有效了,当然这条语句是无法这么优化的。

转载于:https://www.cnblogs.com/Joy-Hu/p/8296264.html

你可能感兴趣的文章
CentOS 7.0 配置varnish缓存
查看>>
Java Service Wrapper简介与使用
查看>>
在Android中进行单元测试遇到的问题
查看>>
2.7. SNMP
查看>>
Android全局代理软件ProxyDroid和TransProxy源码分享
查看>>
C# WinForm开发系列 - ADO.NET
查看>>
SQL Server误区30日谈-Day23-有关锁升级的误区
查看>>
人人都是 DBA(XV)锁信息收集脚本汇编
查看>>
将不确定变为确定~MVC3的ValidateInput属性失灵了
查看>>
[LeetCode] Paint House II 粉刷房子之二
查看>>
[LeetCode] Number Complement 补数
查看>>
设计一个有getMin功能的栈
查看>>
[LintCode] Maximum Gap 求最大间距
查看>>
RegeX的早期版本
查看>>
Redis 小白指南(二)- 聊聊五大类型:字符串、散列、列表、集合和有序集合...
查看>>
零元学Expression Blend 4 - Chapter 23 Deep Zoom Composer与Deep Zoom功能
查看>>
C#~异步编程再续~async异步方法与同步方法的并行
查看>>
Windows下的字体美化
查看>>
13.9. Health Status
查看>>
Unable to execute dex: Multiple dex files define Lcom/kenai/jbosh/AbstractAttr
查看>>