在学校学习MySQL课程的时候没认真,直到前些时间面试官问道了解MySQLl索引吗?也只能尴尬回答是为了方便查询,于是花时间重新学习下,留下记录方便复习。
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针(也可以说索引是帮助MySQL高效获取数据的数据结构)。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
索引非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。索引能够轻易将查询性能提高好几个数量级,总的来说就是可以明显的提高查询效率。
索引的好处:
1.提高数据检索的效率,降低数据库的IO(数据库文件的读写)成本。
2.在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
我们知 道,每个索引中的数据都是按照索引键键值进行排序后存放的,所以,当Query 语句中包含排序分组操作时,如果排序字段和索引键字段刚好一致,MySQL Query Optimizer 就会告诉 mysqld 在取得数据后不用排序了,因为根据索引取得的数据已经满足客户的排序要求。
那如果是分组操作呢?分组操作没办法直接利用索引完成。但是分组操作是须要先进行排序然后分组的,所以当Query 语句中包含分组操作,而且分组字段也刚好和索引键字段一致,那么mysqld 同样可以利用索引已经排好序的这个特性,省略掉分组中的排序操作。
排序分组操作主要消耗的是内存和 CPU 资源,如果能够在进行排序分组操作中利用好索引,将会极大地降低CPU资源的消耗。
索引的坏处:
1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
2.索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚集索引那么需要的空间就会更大。
3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
适合简历索引:
1.主键自动建立唯一索引。
2.频繁作为查询条件的字段应该建立索引。
3.查询中与其它表关联的字段,外键关系建立索引。
4.查询中排序的字段,排序字段若通过索引去访问将大大提高排序效率
5.查询中统计或者分组字段
不适合建立索引:
1.表数据较少的
2.经常增删改查的表或者字段
3.where条件里用不到的字段
4.过滤性(条件中存在>,<等)不好的不适合建立索引
5.唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
索引的建立应该是随机应变而不是盲目添加。
1.从存储结构上来划分:BTree索引(B-Tree或B+Tree索引),Hash索引,full-index全文索引.R-Tree索引。这里所描述的是索引存储时保存的形式
2.从应用层次来分:普通索引,唯一索引,复合索引
3、根据中数据的物理顺序与键值的逻辑(索引)顺序关系:聚集索引,非聚集索引
平时讲的索引类型一般是指在应用层次的划分。
普通索引:即一个索引只包含单个列,一个表可以有多个单列索引
唯一索引:索引列的值必须唯一,但允许有空值
复合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并
聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。
索引的创建有三种方法分别是在创建数据表时、CREATE 在已经存在的表上创建索引、ALTER TABLE 在已经存在的表上创建索引
1.在创建数据表时创建索引
CREATE TABLE 表名(
字段名1 字段类型 [完整性约束条件],
字段名2 字段类型 [完整性约束条件],
...,
INDEX [UNIQUE|FULLTEXT|SPATIAL] 索引名 (字段名[(长度)] [ASC|DESC])
);
2.CREATE在已经存在的表上创建索引
CREATE[UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名 ON 表名 (字段名[(长度)] [ASC|DESC]);
3.ALTER TABLE在已经存在的表上创建索引
ALTER TABLE 表名 ADD [UNIQUE|FULLTEXT|SPATIAL] INDEX 索引名 (字段名([长度]) [ASC|DESC]);
删除索引
DROP INDEX 索引名 ON 表名;
注:[]表示可选即可有可无,|表示或者即选择其中一个
UNIQUE:(unique),可选参数,表示索引为唯一索引。
FULLTEXT:(fulltext) ,可选参数,表示索引为全文索引。
SPATIAL:(spatial) ,可选参数,表示索引为空间索引。
INDEX | KEY:(index | key), 必选参数,用于指定字段为索引的,用户在选择时,只需要二选一即可。
[索引名]:可选参数,其作用是给创建的索引取新名称。(起到方便使用的目的)
被选定的字段名:必选参数,被用作索引的对应的字段名称,该字段必须被预先定义。
长度:可选参数,其指索引的长度,必须是字符串类型才可以使用。(比如:电话号码)
[ASC | DESC]:(asc | desc),可选参数,ASC 表示升序排列,DESC 表示降序排列。
例子:
1.创建普通索引(普通索引创建不需要任何[UNIQUE|FULLTEXT|SPATIAL]等任何参数进行约束)。
创建的表名为 score 的数据表,并在该表的 id 字段上建立名称为 score_id 的 ’ 普通索引 ',SQL语句如下:
CREATE TABLE score(
`id` int(11) AUTO_INCREMENT auto_increment primary key not null,
`username` varchar(30),
`password` varchar(30),
INDEX `a` (`id` ASC)
);
2.创建唯一索引
创建唯一索引时,使用 UNIQUE 参数对 INDEX | KEY 进行约束
与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。
如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。这么做的好处:一是简化了 MySQL对这个索引的管理工作,这个索引也因此而变得更有效率;二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经在某个记录的这 个字段里出现过了;如果是,MySQL将拒绝插入那条新记录。也就是说,唯一索引可以保证数据记录的唯一性。
事实上,在许多场合,人们创建唯一索引的目的往往不是为了提高访问速度,而只是为了避免数据出现重复。
主索引:必须为主键字段创建一个索引,这个索引就是所谓的"主索引"(mysql中主键会自动创建索引)。
主索引 与 唯一索引的唯一区别是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE。
创建的表名为 address 的数据表,并在该表的 id 字段上建立名称为 address_id 的 ’ 唯一索引 ',SQL语句如下:
CREATE TABLE address(
`id` int(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
`name` VARCHAR(30) NOT NULL,
`address` VARCHAR(100) NOTNULL,
UNIQUE INDEX `address_id` (`id` ASC)
);
3.创建全文索引
全文索引只能作用在 CHAR、VARCHAR、TEXT、类型的字段上。创建全文索引需要使用 FULLTEXT 参数进行约束。
MySQL从3.23.23版开始支持全文索引和全文检索,fulltext索引仅可用于 MyISAM 表;他们可以从CHAR、VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或CREATE INDEX被添加。
对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,然后创建索引,其速度比把资料输入现有FULLTEXT索引的速度更为快。不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。如果字段里存放的是由几个、甚至是多个单词构成的较大段文字,普通索引就没什么作用了。这种检索往往以LIKE %word%的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,响应时间就会很长。
这类场合正是全文索引(full-text index)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数据记录。全文索引即可以随数据表一同创建,也可以等日后有必要时再使用命令添加。
有了全文索引,就可以用SELECT查询命令去检索那些包含着一个或多个给定单词的数据记录了。下面是这类查询命令的基本语法:
SELECT * FROM table_name WHERE MATCH(column1, column2) AGAINST('word1', 'word2', 'word3')
上面这条命令将把column1和column2字段里有word1、word2和word3的数据记录全部查询出来。
例:创建的表名为 cards 的数据表,并在该表的 name 字段上建立名称为 cards_name 的 ’ 全文索引 ',SQL语句如下
CREATE TABLE cards(
`id` int(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
`name` VARCHAR(30) NOT NULL,
`info` VARCHAR(100) NOTNULL
);
CREATE FULLTEXT INDEX `cards_name` ON cards (`name` ASC)
4.创建单列索引(即在数据表的单个字段上创建索引。创建该类型索引不需要引入约束参数,用户在建立时只需要指定单列字段名,即可创建单列索引)。
多个单列索引与单个多列索引的查询效果不同,因为执行查询时,MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。
例:创建的表名为 telephone 的数据表,并在该表的 tel 字段上建立名称为 tel_num 的单列索引,SQL 语句如下:
CREATE TABLE telephone(
`id` int(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
`name` VARCHAR(30) NOT NULL,
`tel` VARCHAR(100) NOTNULL
);
ALTER TABLE telephone ADD INDEX `tel_num` (`tel` asc);
5.创建多列索引(即在数据表的多个字段上创建索引。与上述单列索引类似,创建该类型索引不需要引入约束参数)。
多个单列索引与单个多列索引的查询效果不同,因为执行查询时,MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。
例:创建的表名为 information 的数据表,并在该表的 name 和 sex 字段上建立名称为 info 的多列索引,SQL 语句如下:
CREATE TABLE information(
`id` int(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
`name` VARCHAR(30) NOT NULL,
`sex` VARCHAR(30) NOTNULL
);
ALTER TABLE information ADD INDEX `info` (`name`,`sex`);
注意:在多列索引中,只有查询条件中使用了这些字段中的第一个字段(即上面示例中的 name 字段),索引才会被使用。
触发多列索引的条件是用户必须使用索引的第一字段,如果没有用到第一字段,则索引不起任何作用,用户想要优化查询速度,可以应用该类索引形式。
例:组合(复合)索引 —(‘最左前缀’原则)
针对 title 和 time 建立一个组合索引:alter table info add index index_title_time
(title
(50),time
(10))。建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:
–title,time
–title
为什么没有time这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:
使用到上面的索引:
SELECT * FROM article WHREE title=‘测试’ AND time=1234567890;
SELECT * FROM article WHREE title=‘测试’;
–不使用上面的索引
SELECT * FROM article WHREE time=1234567890;
6.创建空间索引
创建空间索引,需要添加 SPATIAL 参数进行约束。
同样,必须说明的是,只有 MyISAM 类型的表支持该类型 ‘ 空间索引 ’。而且,索引字段必须有非空约束。
创建的表名为 list 的数据表,并在该表的 goods 字段上建立名称为 listinfo 的空间索引,这里 goods 字段有非空约束,符合条件,SQL 语句如下:
CREATE TABLE list(
`id` int(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
`name` VARCHAR(30) NOT NULL,
`goods` VARCHAR(30) NOTNULL
);
CREATE SPATIAL INDEX `listinfo` ON list (`goods`);
注意: goods 字段上已经建立名称为 listinfo 的空间索引,其中 goods 字段必须不能为空,且数据类型是 GEOMETRY,该类型是空间数据类型。
空间类型不能用其他类型代替,否则在生成空间素引时会产生错误且不能正常创建该类型索引。
另外:INDEX | KEY:(index | key), 必选参数,用于指定字段为索引的,用户在选择时,只需要二选一即可。
具体什么时候选 INDEX ,什么时候选 KEY ?
参照两者区别:
1). key :是数据库的物理结构,它包含两层意义:一是约束(偏重于约束和规范数据库的结构完整性)、二是索引(辅助查询用的)。包括primary key, unique key, foreign key 等。
primary key 有两个作用,一是约束作用(constraint),用来规范一个存储主键和唯一性,但同时也在此key上建立了一个index;
unique key 也有两个作用,一是约束作用(constraint),规范数据的唯一性,但同时也在这个key上建立了一个index;
foreign key也有两个作用,一是约束作用(constraint),规范数据的引用完整性,但同时也在这个key上建立了一个index;
2). index:是数据库的物理结构,它包含一层意义:它只是索引(辅助查询用的),它创建时会在另外的表空间(mysql中的innodb表空间)以一个类似目录的结构存储。
因此,索引只是索引,它不会去约束索引的字段的行为(那是key要做的事情)。
3). 最后的释疑:
1. 我们说索引分类,分为主键索引、唯一索引、普通索引(这才是纯粹的index)等,也是基于是不是把index看作了key。
比如 create table t(id int, unique index inx_tx_id (id)); — index当作了key使用,因为前面的 unique 赋予了 ‘约束’,使其具有和 key 一样的作用。
2. 最重要的也就是,不管如何描述,理解index是纯粹的index,还是被当作key,当作key时则会有两种意义或起两种作用。
内容参考:https://www.cnblogs.com/wulw829/p/11316562.html
最左前缀匹配原则:
非常重要的原则,对于组合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配(指的是范围大了,有索引速度也慢),比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
总结:
1.条件一定是建立了索引的字段,如果条件使用的字段根本就没有创建索引,那么索引不生效
2.如果条件是一个范围,随着范围的值逐渐增大,那么索引能发挥的作用也越小
3.如果使用like进行模糊查询,那么使用a%的形式能命中索引,%a形式不能命中索引
4.尽量选择区分度高的字段作为索引列
5.索引列不能在条件中参与计算,也不能使用函数
6.在多个条件以and相连的时候,会优点选择区分度高的索引列来进行查询
在多个条件以or相连的时候,就是从左到右依次判断
7.制作联合索引
(1).最左前缀原则 a,b,c,d 条件是a的能命中索引,条件是a,b能命中索引,a,b,c能命中,a,c… 只要没有a就不能命中索引
如果在联合查询中,总是涉及到同一个字段,那么就在建立联合索引的时候将这个字段放在最左侧
(2).联合索引 如果按照定义顺序,从左到右遇到的第一个在条件中以范围为条件的字段,索引失效
尽量将带着范围查询的字段,定义在联合索引的最后面
drop index
;如果我们查询的条件总是多个列合在一起查,那么就建立联合索引
create index ind_mix on s1(id,email)
select * from s1 where id = 1000000 命中索引
select * from s1 where email = ‘eva1000000@oldboy’ 未命中索引
但凡是创建了联合索引,那么在查询的时候,再创建顺序中从左到右的第一列必须出现在条件中
select count() from s1 where id = 1000000 and email = ‘eva10%’; 命中索引
select count() from s1 where id = 1000000 and email like ‘eva10%’; 可以命中索引
范围 :
select * from s1 where id >3000 and email = ‘eva300000@oldboy’; 不能命中索引
8.条件中涉及的字段的值必须和定义表中字段的数据类型一致,否则不能命中索引
大概就这样后面在补充…