mysql索引

一、索引的基本概述

1、什么是索引

索引是创建表上的,是对数据库表中一列或多列的值进行排列的一种结构,使用索引可快速访问数据库表中的特定信息。
举个例子吧:如果把数据库看成一本词典,索引就相当于一本词典的目录,我们可以通过索引快速的找到词典中的词。对于数据库来说,可以通过索引快速查找表中的数据。

2、索引建立的位置及结构存放位置

1)索引是建立在表上的
2)索引一般以文件形式存在磁盘中(也可以存于内存中),存储的索引的原理大致概括为以空间换时间,数据库在未添加索引的时候进行查询默认的是进行全量搜索,也就是进行全局扫描,有多少条数据就要进行多少次查询,然后找到相匹配的数据就把他放到结果集中,直到全表扫描完。而建立索引之后,会将建立索引的KEY值放在一个n叉树上(B+树)。因为B树的特点就是适合在磁盘等直接存储设备上组织动态查找表,每次以索引进行条件查询时,会去树上根据key值直接进行搜索。
其中:(1)Innodb引擎
.frm 文件存储表结构
.ibd 文件存储数据和索引
(2)myIsam引擎:
.myi 文件存储索引
.myd文件存储数据
.frm 文件存储表结构

3、索引的优点

(1)建立索引可以有效地缩短检索的时间
(2)建立索引可以加快表与表之间的连接
(3)为用来排序或者分组的字段加上索引可以加快索引的分组及排序
(4)建立索引的列可以保证行的唯一性

总之建立索引的目的:加快对表中的记录的查询和排序

4、索引的缺点

在此处想到一句话:事物都有两面性(相对论),索引也是不例外的
(1)创建索引和维护索引需要耗费时间,并且随着数据量的增加而增加
(2)索引需要占用物理的空间,并且一个索引都占用一定的空间(数据表占用的是数据库的空间)
(3)会降低表增删改的效率,因为每次进行增删改索引要进行动态维护,造成数据的维护速度降低了,这就导致时间变长

从此处我们也可以看出来,不是啥时候都可以选择索引,要充分考虑到上述的优缺点。
当数据库中的数据量大时,查询的响应速度不能满足自己的需求,此时我们可以考虑使用合理的索引来提升查询速度。

5、索引的种类

(1)普通索引:在创建普通索引时,不附加任何限制条件。这类索引可以创建在任何数据类型中,其值是否唯一和非空由字段本身的完整性约束条件决定。建立索引以后,查询时可以通过索引进行查询。

(2)唯一性索引:使用UNIQUE参数可以设置索引为唯一性索引。**在创建唯一性索引时,限制该索引的值必须是唯一的。**通过唯一性索引。可以更快速的确定某条记录。主键就是一种特殊唯一性索引。

(3)全文索引:使用FULLTEXT参数可以设置索引为全文索引。全文索引只能创建在char,varchar或text类型的字段上。查询数据量较大的字符串类型的字段时,使用全文索引可以提高查询速度。MySQL数据库中3.23.23版开始支持全文索引,但只有MyISAM存储引擎支持全文索引。在默认情况下,全文索引的搜索执行方式不区分大小写。但索引的列使用二进制排序后,可以执行区分大小写的全文索引。

(4)单列索引:在表中的单个字段上创建索引。单列索引只根据该字段进行索引。单列索引可以是普通索引,也可以是唯一性索引,还可以是全文索引。只要保证该索引只对应一个字段即可。

(5)多列索引:多列索引是在表的多个字段上创建一个索引。该索引指向创建时对应的多个字段,可以通过这几个字段进行查询。但是,只有查询条件中使用了这些字段中第一个字段时,索引才会被使用。

(6)空间索引:使用SPATIAL参数可以设置索引为空间索引。空间索引只能建立在空间数据类型上,这样可以提高系统获取空间数据的效率。MySQL中的空间数据类型包括GEOMETRY和POINT、LINESTRING和POLYGON等。目前只有MyISAM存储引擎支持空间检索,而且索引的字段不能为空值

(7)主键索引:索引建立在主键上。 当然反之则是辅助索引
主键索引:
InnoDB :叶子节点存储主键和这个主键所对应的所有数据。
MyISAM :叶子节点存储的是主键(建立索引的属性)和数据的地址。
辅助索引:
InnoDB :叶子节点存储建立索引的属性和属性所对应的主键值。
MyISAM :叶子节点存储建立索引的属性和属性对应的数据的地址。

6、底层数据结构

B+树索引和哈希索引
其中哈希索引:无法做范围查询但是查询单个字段速度快

7、索引的设计原则

(1)为经常需要分组、排序和联合操作的字段建立索引
(2)限制索引的数目,
(3)尽量使用数量少的索引
(4)尽量使用前缀来索引
(5)选择唯一性索引
(6)删除不再使用或者很少使用的索引
(7)为常作为查询条件的字段建立索引
注意:选择索引的最终目的是提高查询的速度。

二、索引的创建和修改删除等命令

1、索引的创建

创建表时直接创建
mysql索引_第1张图片

(1)创建普通索引

mysql索引_第2张图片

(2)创建唯一性索引

mysql索引_第3张图片

(3)创建全文索引

mysql索引_第4张图片

(4)创建单例索引

mysql索引_第5张图片

(5)创建多例索引

mysql索引_第6张图片

(6)创建空间索引

mysql索引_第7张图片

2、在已存在的表上创建索引

mysql索引_第8张图片
在这里插入图片描述

(1)创建普通索引

在这里插入图片描述

(2)创建唯一性索引

mysql索引_第9张图片

(3)创建全文索引

在这里插入图片描述
mysql索引_第10张图片

(4)创建单列索引

mysql索引_第11张图片

(5)创建多列索引

mysql索引_第12张图片

(6)创建空间索引

mysql索引_第13张图片

3、用ALTERTABLE语句来创建索引

mysql索引_第14张图片

(1)创建普通索引

在这里插入图片描述

(2)创建唯一性索引

mysql索引_第15张图片

(3)创建全文索引

mysql索引_第16张图片

(4)创建单列索引

在这里插入图片描述

(5)创建多列索引

mysql索引_第17张图片

(6)创建空间索引

mysql索引_第18张图片

4、删除索引

在这里插入图片描述
或者

alter table '表名' drop index '索引名';

5、索引的查询

show indexes from '表名';
或者
show keys from '表名';

三、常见的索引情况

1、隐式转换导致索引失效

这一点应当引起重视,也是开发中经常会犯的错误。
由于表的字段name定义为varchar(20),但在查询时把该字段作为number类型以where条件传给Mysql,这样会导致索引失效。
强转会引起索引失效:
user id name
index(name); varchar(20)
错误的例子:

select * from test where name = 13333333333; 

我们需要对name先强转再比较
100行数据 把100行数据的name属性分别取出来先强转在比较。
原因:需要把所有的数据对应的name属性取出进行强转。
需要将每一行数据都拿出来进行强换之后再比较。
强转之后改变了原有字段的比较规则
正确的例子:

select * from test where name='13333333333'; //能用到索引 

2、对索引列进行运算导致索引失效

我所指的对索引列进行运算包括(+,-,*,/,! 等)
index(id)
错误的例子:

select * from test where id - 1 < 9;

需要将每一个元组中的id值先取出,再减一然后和9再去比较
正确的例子:

select * from test where id < 10;//能用到索引
 select * from test where id = 9+1;//能用到索引

3、使用MySQL内部函数导致索引失效

对于这样情况应当创建基于函数的索引。
错误的例子:

select * from test where 函数(id)=10;

说明,此时id的索引已经不起作用了
要使用索引的话需要将:k(x) = y; → x = R(y);
错误的例子:

select * from test where id < 函数(age);  还是用不到索引

需要将每一个元组中的id值先取出,再通过函数计算,计算之后的值在和10比较

4、以下使用会使索引失效,应避免使用

(1)使用 <> 、not in 、!=

index(id)

select * from id not in (12,13,15); //用不到 没有明确查询条件
select * from id  in (12,13,15);   // 能用到

(2)like “%_” 百分号在前

可采用在建立索引时用reverse(columnName)这种方法处理

%:任意个任意字符

index(name)

select * from name like '%a';  //由于字符串的最左比较法  用不到

字符串的索引是如何建立:从左到右一个字符一个字符进行大小比较然后得出的B+树的结构。

select * from name like 'a%';  //由于字符串的最左比较法  能用到

5、用OR关键字查询语句

查询语句的查询条件中只有OR关键字,且OR前后的两个条件中列都是索引时,查询中才会使用索引。否则,查询将不使用索引。

  name = "tom" or()  age < 90;  ---->index(name)   index(age);
  name = "tom" and  age < 90;   ---->  index(name,age)
  

四、练习题

一、根据表结构,判断当分别执行如下5条语句时想要使用索引,分别应该如何建立。

//创建表
    create table stu_index1 (id int primary key,name varchar(20),score double);
    insert stu_index1 values(1,'liu',89);
    insert stu_index1 values(2,'sam',78);
    insert stu_index1 values(3,'jim',95);
 //根据哪个属性筛选的就要在哪个属性上建立索引

1、explain select * from stu_index where id = 3\G
InnoDB:由于主键索引默认创建,所以不需要任何操作;
叶子节点:存储主键和所有的数据;
MyISAM:能用到索引就行,由于主键索引默认创建,所以不需要任何操作;
叶子节点:存储建立索引的属性和数据相应的地址;
要求只查询一次:index(id,name,score);

2、explain select * from stu_index where name=‘liu’\G
InnoDB:index(name); (查询两次)
叶子节点存储建立索引的属性的值和所对应的主键的值;
查询一次:index(name,score);
MyIsam:index(name) (查询两次)
叶子节点存储:建立索引的属性和数据对应的地址。
查询一次:index(name,id,score);

3、explain select * from stu_index where name = ‘liu’ and score = 89;
InnoDB:index(name,score); 可以 ;index(score,name); 因为mysql内部有优化,所以也可以。(查询一次)
叶子节点存储建立索引的属性的值和所对应的主键的值。
MyIsam:index(name,score); index(score,name); (查询两次)
叶子节点存储:建立索引的属性和数据对应的地址。
查询一次:index(name,score,id);

4、explain select id from stu_index where name=‘liu’\G
InnoDB: index(name); (查询一次)
叶子节点存储建立索引的属性的值和所对应的主键的值。
MyIsam:index(name) ;(查询两次)
叶子节点存储:建立索引的属性和数据对应的地址。
查询一次: index(name,id); 对 index(id,name); 错 (原因:无法进入B+树的结构)

5、explain select score from stu_index where name=‘liu’\G
MyIsam/InnoDB:查询一次:index(name,score);
原因:两个引擎下的索引的叶子节点都存储建立索引的属性的值。

二、根据表结构,判断当分别执行如下语句时想要使用索引,应该如何建立。

mysql> create table orderlist(name varchar(20) not null,
    -> productid int not null,
    -> date timestamp);

1、explain select * from orderlist where name =‘Tom’ order by date\G
InnoDB:index(name,data);对;index(data,name);错;(查询两次)
MyISAM:index(name,data);对;index(data,name);错;(查询两次)

三、根据以下表结构和建立的索引分别判断以下sql语句能否使用到所建立的索引,能用到回答能,不能用到则回到不能。

CREATE TABLE `student_index` (
	`id` int(11) NOT NULL,
	`name` varchar(255) DEFAULT NULL,
	`cid` int(11) DEFAULT NULL,
	`school` char(20) NOT NULL DEFAULT '',
	KEY `name_cid_INX` (`name`,`cid`,`school`)
	) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into student_index values
	(1,'weixin',12,'caijing'),
	(2,'weixin',13,'ligong'),
	(3,'weixin',14,'gongye');


最左前缀原则 :从左往右进行比较的
要使用索引的话:左边第一个属性一定不能缺少。
要是想把索引用完全:从左到右一个属性都不能少,否则索引将使用不完全。
1、explain select * from student_index where name = ‘abc’ and cid = 123 and school = ‘ligong’ \G

2、explain select * from student_index where name = ‘abc’ and cid = 123\G

explain select * from student_index where cid = 123 and name = ‘abc’ \G
能,因为MySQL会根据索引对SQL语句进行优化;该语句会被优化为与上面SQL语句相同的语句;
3、explain select * from student_index where name = ‘abc’\G

4、.explain select * from student_index where name = ‘abc’ and school=‘ligong’\G

5、explain select * from student_index where cid = 123 and school = ‘ligong’\G
不能

四、联合查询中如何使用索引,以下两张表均在stu_id 字段上添加索引 index(stu_id)。判断哪张表的索引能用到。
表的结构如下:
mysql索引_第19张图片
mysql索引_第20张图片
MySQL会首先判断rb1(别名表a)和rb2(别名表b)哪个表小,这里表小主要指的是行数少,很显然rb2表小,MySQL会对rb2表进行整表遍历,然后在a表上根据stu_id字段进行查询,所以rb2表就是小表,无论如何都是要整表遍历的,是使用不到索引的,但是大表rb1表的stu_id字段创建索引,就能使用到了!所以在链接查询的时候,小表总是要整表搜索的,建立索引没有用,大表创建索引是能提高查询效率的,小表决定查询次数,大表决定查询时间(有索引就快,没有索引就慢)能不能用到索引,用到的是那张表的索引。

1、explain select * from rb1 a,rb2 b where a.stu_id = b.stu_id\G
where a.stu_id = b.stu_id底层处理:
把b中的所有的stu_id取出来,分别和a中的stu_id作比较;
a.stu_id in (23,24,25);比较三次
把a中的所有的stu_id取出来,分别和b中的stu_id作比较;
b.stu_id in (23,24,25,40,41,42);比较六次
MySQL采用第一种做法:把小表中的所有的数据取出来然后和大表中的数据做对比;
rb1使用到索引;rb2没有使用到索引;即大表能用到索引,小表使用不到索引;

2、explain select * from rb1 a join rb2 b on a.stu_id = b.stu_id where a.stu_id < 25\G
此时rb1是小表:(<25)的数据只有两行,rb2的数据有三行;所以理应情况下应该是:rb2使用到索引;rb1没有使用到索引;但是真实情况是两张表都使用到了索引,原因是:
rb2使用到索引:此时rb2表是大表,能使用到索引;
rb1使用到索引:因为SQL语句执行(where a.stu_id < 25)时对rb1表使用了索引;

你可能感兴趣的:(mysql索引)