mysql 索引扫盲篇

Posted microhex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql 索引扫盲篇相关的知识,希望对你有一定的参考价值。

项目中有个记录设备路径信息的表数据越来越大,到目前为止已经超过20w数据的信息了,才几天功夫发现有些不得了,终端响应速度非常慢,所以就赶紧学习一下数据库中的索引知识,来缓解一下查询速度。

基本概念

索引是一种特殊的文件,按照某种算法记录了数据库表中数据的关键信息,通过查找该文件,能达到降低查询时间的目的。

索引用于快速找出某列中有特定值的行,不使用索引,mysql必须从第一条记录开始完整读表,知道找出相关的行,表越大,查询的数据所花费的时间就越多,如果表中查询的列有一个索引,MySQL能快速的到达一个位置去搜索数据文件,而不必查看所有的数据,那么将会节省很大一部分时间。

索引存储类型

上面已经说过了,索引也是文件,只是比较特殊,分为两种:BTREEHASH。具体为啥,先了解一下即可,即树和哈希值来存储字段。
MyIsAMInnoDB存储引擎:只支持BTREE索引,也就是默认使用BTREE,不能够更换;
MEMORYHEAP存储引擎:支持HASHBTREE索引

索引的优势

  1. 所有的Mysql列类型都可以被索引,也就是可以给任意字段设置索引;
  2. 大大加快数据的查询时间

索引的缺点

 a. 创建索引和维护索引需要耗费时间,并且随着数据量的增加所耗费的时间也会增加;
 b. 索引页需要占用空间,数据表中的数据也会有最大上限值;如果存在大量的索引,索引文件可能会比数据文件更快达到上限值;
 c. 当对表的数据进行增加、修改、删除时,索引也要动态维护,降低了数据的维护速度。

单列索引

一个索引只包含单个列,但是一个表中可以包含多个单列索引。
先建个表:

CREATE TABLE t_student (
	id int not null,
	name VARCHAR(255) not null,
	age int DEFAULT 0,
	address VARCHAR(255) null
);

先建一个数据表t_student,包含四个字段id,name,age,address

普通索引

MySQL中基本索引类型,没有限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点;建表时直接创建,我们以address建立索引

CREATE TABLE t_student (
	id int not null,
	name VARCHAR(255) not null,
	age int DEFAULT 0,
	address VARCHAR(255) null,
	INDEX(address)
);

或者

CREATE TABLE t_student (
	id int not null,
	name VARCHAR(255) not null,
	age int DEFAULT 0,
	address VARCHAR(255) null,
	KEY(address)
);

或者如果表已经存在,那么可以使用:

ALTER TABLE t_student ADD INDEX ageIndex(age)
CREATE INDEX ageIndex on t_student(age)

上面的含义为以age为索引,创建名为ageIndex的索引;

可以使用命令查看一下:

show index from t_student ;

可以查看到:

字段字段含义
Table创建索引的表
Non-unique表示索引非唯一,1代表非唯一索引 0为唯一索引, 意思就是该索引是不是唯一索引
Key-name索引名称
Seq_in_index表示该字段在索引的位置,单列索引时该值为1,组合索引为每子字段在索引定义的顺序
Column_name表示定义索引的列字段
Sub_part表示索引的长度
Null表示该字段是否可以为空值
Index_type表示索引类型

唯一索引

索引列中的值必须是唯一的,但是允许为空值;关键字为UNIQUE

CREATE TABLE t_student (
	id int not null,
	name VARCHAR(255) not null,
	age int DEFAULT 0,
	address VARCHAR(255) null,
	UNIQUE INDEX idIndex(id) 
);

或者表已经存在,那么应该为:

CREATE UNIQUE INDEX idIndex on t_student(id desc)
ALTER TABLE t_student add UNIQUE INDEX idIndex(id asc) 

对Id建立了唯一索引,并且所索引名为idIndex

主键索引

特殊的唯一索引,不允许有空值。关键字 PRIMARY

CREATE TABLE t_student (
	id int not null,
	name VARCHAR(255) not null,
	age int DEFAULT 0,
	address VARCHAR(255) null,
	PRIMARY KEY idIndex(id) 
);

这个类似我们以前创建的SQL语句,创建数据时:

create table object( 
	id int primary key auto_increment,
	//...其他数据
)

此时我们默认创建了以id为主键的主键索引。
如果表已经存在,那么可以这样:

ALTER TABLE t_student ADD PRIMARY KEY (id)

对Id建立了主键索引,并且所索引名为idIndex

组合索引

在表中多个字段组合上创建的索引,只有在查询条件中使用这些字段做为查询字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。

还是先建表:

CREATE TABLE t_student (
	id int not null,
	name VARCHAR(255) not null,
	age int DEFAULT 0,
	address VARCHAR(255) null
);

我现在要创建(id,name,age)三列为组合索引,那么应该这么写:

CREATE UNIQUE INDEX mulitIndex on t_student(id desc, name, age)

或者:

ALTER TABLE t_student add UNIQUE INDEX idIndex(id asc,name, age) 

使用 show index from t_student 查看一下索引结构:

可以看到三个字段都同时属于idIndex 这个索引
对于组合索引,只有查询时才会起作用,对于这个最左前缀集合,我们可以用上面这个例子,我们的组合索引是(id,name,age),那么在查询时,只有存在查询id时,这个组合索引才会生效,单独只有name或者age时,索引无效。那么怎么知道我在查询过程是否有效呢?
使用EXPLAIN 关键字,比如我们在查询的情况下:
a. 组合索引有效的情况:

EXPLAIN SELECT * from t_student where id = 1 and name = 'Tom'

得到的结果为:

如果我们的查询条件中没有id,只有name或者age呢?

针对上面的字段的含义,大概为:

字段名称字段含义
idSELECT识别符。这是SELECT的查询序列号,也就是一条语句中,该select是第几次出现。在次语句中,select就只有一个,所以是1
select_type所使用的SELECT查询类型,SIMPLE表示为简单的SELECT,不是用UNION或子查询,就为简单的SELECT。
也就是说在该SELECT查询时会使用索引。其他取值:
PRIMARY:最外面的SELECT在拥有子查询时,就会出现两个以上的SELECT。
UNION:union(两张表连接)中的第二个或后面的select语句 SUBQUERY:在子查询中,第二SELECT。
table数据表的名称 按照被读取的先后顺序
type指定本数据表和其他数据表之间的关联关系,该表中所有符合检索值的记录都会被取出来和从上一个表中取出来的记录作联合。ref用于连接程序使用键的最左前缀或者是该键不是 primary key 或 unique索引(换句话说,就是连接程序无法根据键值只取得一条记录)的情况。当根据键值只查询到少数几条匹配的记录时,这就是一个不错的连接类型
possible_keyMySQL在搜索数据记录时可以选用的各个索引 ,我们这里只有一个idIndex
key实际选用的索引
key_len显示了mysql使用索引的长度 。当key字段为null时,索引的长度就是null
key_len的值可以告诉你在联合索引中mysql会真正使用了哪些索引
ref给出关联关系中另一个数据表数据列的名字。常量(const),以为id为1
rowsmysql在执行这个查询时预计会从这个数据表中读取的数据行数
filtered按表条件过滤的行的百分比,这个上面是100,则意味只有1种情况
Extra额外的信息

通过查看possible_key和key我们就知道在查询的过程中使用了哪些索引了。

全文索引

MyISAM引擎上使用,只能作用到CHAR、VARCHAR、TEXT类型字段上使用全文索引。所谓全文索引,就是通过记录某些关键字,来找到某条记录值。关键字FULLTEXT

咋们来创建一下:

 CREATE TABLE t_student (
 	id int not null,
 	name VARCHAR(255) not null,
 	age int DEFAULT 0,
 	address VARCHAR(255) null,
	
	FULLTEXT INDEX FullTextIndex(address)
 ) ENGINE = MyISAM;

或者表已经存在,则可以依赖:

ALTER ALTER t_student add FULLTEXT INDEX FullTextIndex(address)

或者

CREATE FULLTEXT INDEX FullTextIndex on t_student(address)

查询时:

SELECT * FROM t_student WHERE MATCH(address) AGAINST('your key word');

空间索引

空间索引是对空间数据类型的字段建立索引,MySQL的空间数据类型有四种:GEOMETRY、POINT、LINESTRING、POLYGON。
创建空间索引时,使用SPATIAL关键字。 要求:引擎为MyISAM创建空间索引的列,必须将其声明为NOT NULL。
我也不是很清楚,这种空间索引有什么用,暂时记录一下吧。

CREATE TABLE t_student (
 	id int not null,
 	name VARCHAR(255) not null,
 	age int DEFAULT 0,
 	address VARCHAR(255) null,
	x GEOMETRY NOT NULL,	
	SPATIAL INDEX spatIdx(x)
 ) ENGINE = MyISAM;

索引删除

使用 ALTER TABLE 表名 DROP INDEX 索引名

ALTER TABLE t_student DROP INDEX idIndex

使用DROP INDEX 索引名 on 表名

DROP INDEX idIndex  on t_student

参考资料:
1.https://www.cnblogs.com/whgk/p/6179612.html
2.https://www.cnblogs.com/doudouxiaoye/p/5831449.html
3.http://blog.sina.com.cn/s/blog_ae1611930101a063.html
4.https://blog.csdn.net/haluoluo211/article/details/52638457

以上是关于mysql 索引扫盲篇的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 数据库MySQL 的索引和事务(扫盲必备)

「扫盲」elasticsearch(二)—集群安装篇

Mysql-索引类型篇

MySQL 索引--MySQL命令篇

mysql优化篇(基于索引)

Mysql的复合索引,生效了吗?来篇总结文章