目录
一.索引概述
二.索引作用的优缺点
1.优点
2.缺点
三.创建索引的原则依据
四.适用索引的场景
五.索引的分类和创建
1.普通索引
2.唯一索引
3.修改表方式创建
4.组合索引(单列索引与多列索引)
5. 全文索引(FULLTEXT)
六、查看索引
七、删除索引
MySql官方对索引的定义为:索引是帮助MySql高效获取数据的数据结构。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
个人对于MySql索引的理解:在数据之外,数据库系统还维护着满足特定查找算法的数据结构,包括B+树或者Hash表。由于存储引擎表示的是数据在磁盘上面的不同的组织形式,所以索引底层采用哪种数据结构是跟数据库的存储引擎相关的。如果是MyIsam或者是InnoDB存储引擎,那么对应的底层的数据结构为B+树,如果是Memory存储引擎,那么对应的底层的数据结构为Hash表。采用B+树的最根本的原因是由于二叉树的树太高,树太高则直接影响到磁盘IO的次数,影响数据查询的效率,采用B+树的数据结构,可以在某个数据节点里面尽可能多的存储数据,使树的高度尽量的变低,提高效率。日常开发过程中,遇到的比较多的可能就是聚簇索引和联合索引,里面又涉及到了覆盖索引,最左匹配,回表,索引下推等各方面的知识点,在编写SQL语句的时候,我们就可以利用这些点来进行优化,提高数据的查询效率。
索引是数据库优化最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数的MySql的性能优化问题。
总结:做MySQL索引目的即为优化
类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本。
通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的。
虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行 INSERT、 UPDATE、 DELETE。因为更新表时,MSQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
索引随可以提升数据库查询的速度,但并不是任何情况下都适合创建索引。因为索引本身会消耗系统资源,在有索引的情况下,数据库会先进行索引查询,然后定位到具体的数据行,如果索引使用不当,反而会增加数据库的负担。
1.表的主键、外键必须有索引。因为主键具有唯一性,外键关联的是子表的主键,查询时可以快速定位。
2.记录数超过300行的表应该有索引。如果没有索引,需要把表遍历一遍,会严重影响数据库的性能。
3.经常与其他表进行连接的表,在连接字段上应该建立索引。
4.唯一性太差的字段不适合建立索引。
5.更新太频繁地字段不适合创建索引。
6.经常出现在 where 子句中的字段,特别是大表的字段,应该建立索引。
7.索引应该建在选择性高的字段上。
8.索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引。
1.频繁作为 WHERE 查询条件的字段
某个字段在SELECT语句的WHERE条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建索引就可以大幅提升数据查询的效率。
2. 有唯一性限制的字段
字段的值是唯一值的时候优先考虑加上索引,索引本身也可以起到约束作用,且唯一索引查询的速度会比普通索引更快速。
3.经常GROUP BY和ORDER BY的列
索引已经将数据排好序了,因此当我们使用GROUP BY对数据进行分组查询,或者使用ORDER BY对数据进行排序的时候,通过索引就可以十分快速(避免了排序操作) 。如果待排序的列有多个,那么可以在这些列上建立联合索引 。
4.UPDATE、DELETE的WHERE条件列
对数据按照某个条件进行查询后再进行UPDATE或DELETE的操作,如果对WHERE字段创建了索引,就能大幅提升效率。原理是因为我们需要先根据WHERE条件列检索出来这条记录,然后再对它进行更新或删除。如果进行更新的时候,更新的字段是非索引字段,提升的效率会更明显,这是因为非索引字段更新不需要对索引进行维护。
5.DISTINCT字段需要创建索引
有时候我们需要对某个字段进行去重,使用DISTINCT,那么对这个字段创建索引,也会提升查询效率。
6.多表JOIN连接操作时
对WHERE条件创建索引 ,因为WHERE才是对数据条件的过滤。
其次,对用于连接的字段创建索引,并且该字段在多张表中的类型必须一致 。比如 course_id 在 student_info 表和 course 表中都为 int(11) 类型,而不能一个为int另一个为varchar类型。
7. 使用列的类型小的创建索引
类型表示的范围越小:
查询时进行的比较操作越快
索引占用的空间越小,在一个数据页能存放更多的记录,树的高低相对偏低
8.使用字符串前缀创建索引
理由和前一点相同。
截取字段的前一部分内容建立索引,叫做前缀索引。这样在查找时虽然不能精确定位,但是能定位到相应前缀所在位置,然后根据前缀相同记录的主键值回表查询完整的字符串值。节约空间,又减少了字符串的比较时间。
9.区分度高(散列性高)的列适合作为索引
比如性别字段,区分度很低,不建议使用索引。一般区分比超过33%即可。
10.使用最频繁的列放到联合索引的左侧
这样也可以较少的建立一些索引。同时,由于"最左前缀原则",可以增加联合索引的使用率。
11.在多个字段都要创建索引的情况下,联合索引优于单值索引
这种情况下,尽可能建立联合索引。
create table team (id int(10),name varchar(10),cardid varchar(18),phone varchar(11),
address varchar(50),hobby text);
insert into team values (1,'yz','250','5438','beijing','打游戏');
insert into team values (2,'lnj','110','5439','nanjing','背刺');
insert into team values (3,'zwb','666','9527','shenzhen','打篮球');
insert into team values (4,'szh','333','5440','hangzhou','打羽毛球');
insert into team values (5,'ls','555','5445','shanghai','踢足球');
1.1直接创建索引
CREATE INDEX 索引名 ON 表名 (列名[(length)]);
(列名(length)):length是可选项。如果忽略 length 的值,则使用整个列的值作为索引。如果指定使用列前的 length 个字符来创建索引,这样有利于减小索引文件的大小。
索引名建议以“_index”结尾。
create index cardid_index on team (cardid);
show create table team;
1.2修改表方式创建
ALTER TABLE 表名 ADD INDEX 索引名 (列名);
alter table team add index phone_index (phone);
select phone from team;
select phone,name from team;
show create table team\G
1.3创建表的时候指定索引
CREATE TABLE 表名 ( 字段1 数据类型,字段2 数据类型[,...],INDEX 索引名 (列名));
create table test(id int(4) not null,name varchar(10) not null,age int (3),cardid varchar(5) not null,index age_index(age));
show create table test;
CREATE UNIQUE INDEX 索引名 ON 表名(列名);
select * from team;
create unique index address_index on team (address);
create unique index name_index on team (name);
show create table team\G
ALTER TABLE 表名 ADD UNIQUE 索引名 (列名);
alter table team add unique id_index (id);
3.1 CREATE TABLE 表名 ([...],PRIMARY KEY (列名));
create table lcdb1 (id int primary key,name varchar(20));
create table lcdb2 (id int,name varchar(20),primary key (id));
show create table lcdb1\G
show create table lcdb2\G
3.2修改表方式创建
ALTER TABLE 表名 ADD PRIMARY KEY (列名);
alter table lcdb6 add primary key(name);
这里切记做主键索引的时候不能存在其他主键要么删除主键
可以是单列上创建的索引,也可以是在多列上创建的索引。需要满足最左原则,因为select语句的 where条件是依次从左往右执行的,所以在使用select 语句查询时where条件使用的字段顺序必须和组合索引中的排序一致,否则索引将不会生效。
CREATE TABLE 表名 (列名1 数据类型,列名2 数据类型,列名3 数据类型,INDEX 索引名 (列名1,列名2,列名3));
select * from 表名 where 列名1='...' AND 列名2='...' AND 列名3='...';
create table lcdb2 (id int(4),name char(30),genter char(10),age int(4),height decimal(3,1),address char(100),index index_group(id,name));
show create table lcdb\G
insert into lcdb7 values(1,'lnj','男',21,90,'南京');
select * from lcdb2 where name='zhangsan' and id=1;
组合索引创建的字段顺序是其触发索引的查询顺序
select id,name from test3; #会触发组合索引
select name,id from test3; #按照索引从左到右检索的顺序,则不会触发组合索引
适合在进行模糊查询的时候使用,可用于在一篇文章中检索文本信息。
在 MySQL5.6 版本以前FULLTEXT 索引仅可用于 MyISAM 引擎,在 5.6 版本之后 innodb 引擎也支持
FULLTEXT 索引。全文索引可以在 CHAR、VARCHAR 或者 TEXT 类型的列上创建。每个表只允许有一个全文索引。
5.1直接创建全文索引
CREATE FULLTEXT INDEX 索引名 ON 表名 (列名);
select * from team;
create fulltext index suoyin on team(cardid);
desc team;
5.2修改表方式创建
ALTER TABLE 表名 ADD FULLTEXT 索引名 (列名);
alter table team add fulltext index suoyin_index(name);
desc team;
CREATE TABLE 表名 (字段1 数据类型[,...],FULLTEXT 索引名 (列名));
#数据类型可以为 CHAR、VARCHAR 或者 TEXT
create table lcdb8(id int(4),name char(10),genter char(2), age int(2),address char(20
),fulltext index suoyin_index(address));
desc lcdb8;
5.4 使用全文索引查询
SELECT * FROM 表名 WHERE MATCH(列名) AGAINST('查询内容');
select * from team where match(name) against('lnj');
select * from member where name='lnj';
show index from 表名;
show index from 表名\G; 竖向显示表索引信息
show keys from 表名;
show keys from 表名\G;
Table 表的名称
Non_unique 如果索引内容唯一,则为 0;如果可以不唯一,则为 1。
Key_name 索引的名称。
Seq_in_index 索引中的列序号,从 1 开始。 limit 2,3
Column_name 列名称。
Collation 列以什么方式存储在索引中。在 MySQL 中,有值‘A’(升序)或 NULL(无分类)。
Cardinality 索引中唯一值数目的估计值。
Sub_part 如果列只是被部分地编入索引,则为被编入索引的字符的数目(zhangsan如果整列被编入索引,则为 NULL。
Packed 指示关键字如何被压缩。如果没有被压缩,则为 NULL。
Null 如果列含有 NULL,则含有 YES。如果没有,则该列含有 NO。
Index_type 用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)
Comment 备注
1、直接删除索引
DROP INDEX 索引名 ON 表名;
drop index suoyin_index on lcdb8;
desc lcdb8;
2、修改表方式删除索引
ALTER TABLE 表名 DROP INDEX 索引名;
alter table lcdb8 drop index suoyin_index;
3. 删除主键索引
ALTER TABLE 表名 DROP PRIMARY KEY;
alter table lcdb1 drop primary key;