目录
🍄4.5查看SQL语句对索引的使用情况(即查询SQL的查询执行计划QEP):
哥几个来学索引啦~~
🌴1.索引的概念
索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可以快速访问数据库表中的特定信息。
通俗点的例子就是如果将数据库表看成是一本书,那么索引就是书的目录,我们可以根据目录来找到书中指定内容的位置。
我们可以对表中的一列或者多列创建索引,并指定索引的类型,各类索引有各自的数据结构实现。
🌲2.索引的优缺
🍏2.1索引的优点:
🍕a.建立索引的列可以保证行的唯一性,生成唯一的行id。
🍔b.建立索引可以快速定位,有效缩短数据的检索时间,对于提高数据库性能有很大的帮助。
🍟c.建立索引可以加快表与表之间的连接。
🌭d.为用来排序或者分组的字段添加索引可以加快排序和分组的顺序。
🥦2.2索引的缺点:
🍕a.创建索引和维护索引需要时间成本,这个成本随着数据量的增大而加大。
🍔b.创建索引和维护索引需要空间成本,每一条索引都要占据数据库和物理库存储空间,数据量越大,占用的空间也越大(数据表占据的是数据库的数据空间)。
🍟c.会降低表的增、删、改的效率,因为每次增、删、改索引需要索引进行动态维护,导致时间变长。
🥝2.3索引的应用场景:
要考虑对数据库表的某列或某几列创建索引,需要考虑以下几点:
①数据量较大,且经常对这些列进行条件查询。
②该数据库表的插入操作,及对这些列的修改频率较低。
③索引会占用额外的磁盘空间。
满足以上条件时,考虑对表中的这些字段创建索引,可以提高效率。
反之,如果非条件查询列,或者需要经常进行插入、修改的操作,或者磁盘空间不足时,不考虑创建索引。
🌳3.索引的种类
🌺① 普通索引(单列索引):单列索引是最基本的索引,它没有任何限制。
🌻② 复合索引(组合索引):复合索引是在多个字段上创建的索引。复合索引遵守“最左前缀”原则,即在查询条件中使用了复合索引的第一个字段,索引才会被使用。因此,在复合索引中索引列的顺序至关重要。
🌼③ 唯一索引:唯一索引和普通索引类似,主要的区别在于,唯一索引限制列的值必须唯一,但允许存在空值(只允许存在一条空值)。
空值和NULL值其实是两个不同的概念,在MySQL中空值是不占用内存的,而NULL值是占用内存的~~
如果添加索引的列的值存在两个或两个以上的空值,则不能创建唯一性索引。(一般在创建表的时候,要自动设置唯一性索引,需要在字段上加not null)。
如果添加索引的列的值存在两个或两个以上的null值,还是可以创建唯一性索引,只是后面创建的数据不能再插入null值,并且严格意义上此列并不是唯一的,因为存在多个null值。
🍁④ 主键索引:主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。
🌸⑤ 全文索引
在一般情况下,模糊查询都是通过like的方式进行查询的。但是对于海量数据,这并不是一个好方法,在like“value%”可以使用索引,但是对于like“%value%”这样的方式,执行全表查询,如果是对于数据量小的表,不存在性能问题,但是对于海量数据,进行全表扫描的效率是非常低效的,索引like进行模糊查询性能很低。
这种情况下,需要考虑使用全文搜索的方式进行优化。全文搜索在MySQL中是一个fulltext类型索引,fulltext索引在MySQL5.6版本之后支持InnoDB,而之前的版本只支持MyISAM表。
全文索引主要用来查找文本中的关键字,而不是直接与索引中的值比较,fulltext索引和其他索引大不相同,它更像一个搜索引擎,而不是简单的where语句的参数匹配。fulltext索引配合match against操作使用,而不是一般的where语句加like。目前只有char、varchar、text列上可以创建全文索引。
🌵4.索引的使用
🍎4.1建表时创建
语法:
create table 表名(
字段名 数据类型[完整性的约束条件],
......,
[unique | fulltext | spatial] index | key
[索引名] (字段名1[(长度)] [asc | desc]) [using 索引方法]
);
说明:
unique:可选,表示索引为唯一性索引。
fulltext:可选,表示索引为全文索引。
spatial:可选,表示索引为空间索引。
index和key:用于指定字段为索引,两者选其一即可,作用是一样的。
索引名:可选,给创建的索引一个新名称。
字段名1:指定索引对应的字段的名称,该字段必须是前面定义好的字段。
长度:可选,指索引的长度,必须是字符串类型才可以使用。
ASC:可选,表示升序排列。
🍅4.2建表后创建:
alter table 表名 add [unique | fulltext | spatial] index | key [索引名]
(字段名1[(长度)] [asc | desc]) [using 索引方法];
或者
create [unique | fulltext | spatial] index 索引名 on 表名(字段名) [using 索引方法];
🍓4.3查看自己创建的索引:
show index from 表名;
🍒4.4索引的删除:
drop index 索引 on 表名;
或者
alter table 表名 drop index 索引名
创建索引和删除索引都是十分危险的操作,如果针对的是一张数据量巨大的表创建索引,那么会导致创建索引的过程中产生大量的磁盘IO,此时主机可能直接就卡了。
🍄4.5查看SQL语句对索引的使用情况(即查询SQL的查询执行计划QEP):
在select语句前加explain即可:
explain select * from index_name where...
说明:
id:SELECT识别符。这是SELECT的查询序列号。
select_type:SELECT类型。
a.SIMPLE: 简单SELECT(不使用UNION或子查询)
b.PRIMARY: 最外面的SELECT
c.UNION:UNION中的第二个或后面的SELECT语句
d.DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
e.UNION RESULT:UNION的结果
f.SUBQUERY:子查询中的第一个SELECT
g.DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
h.DERIVED:导出表的SELECT(FROM子句的子查询)
table:表名
type:联接类型。
联接类型是SQL性能的非常重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL。
一般来说,得保证查询至少达到range级别。
- system:表仅有一行(=系统表)。这是const联接类型的一个特例。
- const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const用于用常数值比较PRIMARY KEY或UNIQUE索引的所有部分时。
- eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。
- ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列。
- ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
- index_merge:该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
- unique_subquery:该类型替换了下面形式的IN子查询的ref:value IN (SELECT primary_key FROMsingle_table WHERE some_expr);unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
- index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)
- range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用rang
- index:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
- all:对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。
possible_keys:possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。
key:key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len:key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。
ref:ref列显示使用哪个列或常数与key一起从表中选择行。
rows:rows列显示MySQL认为它执行查询时必须检查的行数。
Extra:该列包含MySQL解决查询的详细信息。
- Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
- Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
- range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行。
- Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。
- Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为单一索引一部分的列时,可以使用该策略。
- Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时。
- Using where:WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。
- Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。
- Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。
🌹4.6各类索引的使用:
🌸① 普通索引(单列索引)
(1)直接创建索引:
create index index_name on table_name(col_name1, col_name2 ...);
如果是多个列名,那么这几个列名的索引名相同。
(2)修改表结构的方式来添加索引
alter table table_name add index index_name(col_name1, col_name2 ...);
如果是多个列名,那么这几个列名的索引名相同。
(3)创建表时同时创建索引
create table table_name (
col_name1 ... ,
col_name2 ... ,
...,
index index_name(col_name(len))
);
比如:
create table student (
id int,
name varchar(20),
index id_name,
index name_index (name(20))
);
(4)删除索引
drop index index_name on table_name;
或者
alter table table_name drop index col_name;
使用情况:
🍕1.只涉及到其中的一个字段时,都能使用到索引
🍔2.涉及到多个索引字段时,如果这些索引字段中,存在主键索引,那么只会使用该索引(即:MYSQL优化器会选出并先执行最“严”的索引)
🍟3.涉及到多个索引字段时,如果这些索引字段中,不存在主键索引的话,那么就会使用该使用的索引(注:如果通过其中的部分索引就能准确定位的话,那么其余的索引就不再被使用),先使用哪个索引,再使用哪个索引是由MySQL优化决定的。
🌭4.当对索引字段进行 >, <,>=, <=,not in,between …… and ……,函数(索引字段),like模糊查询%在字段前时,不会使用该索引。
🌼② 复合索引(组合索引)
(1)创建一个复合索引
create index index_name on table_name(col_name1, col_name2,...);
(2)修改表结构的方式添加索引
alter table table_name add index index_name (col_name1, col_name2,...);
使用情况:
🍕1.假设组合索引为a,b,c,那么当SQL中对应有:(a) 或 (a,b) 或 (a,b,c) 的时候,可称为完全满足最左侧原则。
当SQL中查询条件只有(a,c)的时候,可称为部分满足最左原则。
当SQL中没有a的时候,可称为不满足最左侧原则,不满足最左侧原则不会使用索引。
🍔2.从MySQL5.7开始,会自动优化,比如会把(c,b,a)优化为(a,b,c)使之完成满足最左原则,会把(c,a)优化为(a,c)使之部分满足最左原则。即:SQL中条件的先后顺序可以改变。
🍟3.满足部分最左原则,只会走到最左边的索引,到右边的那个索引不会使用到。比如在执行:select * from table_name where a = ? and c = ?;时,到a字段会使用组合索引,到c字段就不会。
🌭4.如果满足了最左原则,但是不满足“索引”自身的使用规范,那么组合索引走到这里之后,不会再往下走了。比如当对索引字段进行 >, <,>=, <=,not in,between …… and ……,函数(索引字段),like模糊查询%在字段前时,不会使用该索引。
🌻③ 唯一索引
(1)直接创建唯一索引:
create unique index index_name on table_name(col_name1, col_name2 ...);
如果是多个列名,那么这几个列名的索引名相同。
(2)修改表结构的方式来添加唯一索引
alter table table_name add unique index index_name(col_name1, col_name2 ...);
如果是多个列名,那么这几个列名的索引名相同。
(3)创建表时同时创建唯一索引
create table table_name (
col_name1 ... ,
col_name2 ... ,
...,
unique index index_name(col_name(len))
);
🌺④ 主键索引
(1)修改表结构的方式来添加主键索引
alter table table_name add parimary key (col_name);
如果是多个列名,那么这几个列名的索引名相同。
(2)创建表时同时创建主键索引
create table table_name (
col_name1 ... ,
col_name2 ... ,
...,
parimary key (col_name(len))
);
🍁⑤ 全文索引
(1)直接创建全文索引:
create fulltext index index_name on table_name(col_name1, col_name2 ...);
如果是多个列名,那么这几个列名的索引名相同。
(2)修改表结构的方式来添加全文索引
alter table table_name add fulltext index index_name(col_name1, col_name2 ...);
如果是多个列名,那么这几个列名的索引名相同。
(3)创建表时同时创建全文索引
create table table_name (
col_name1 ... ,
col_name2 ... ,
...,
fulltext index_name(col_name(len))
);
以上就是MySQL索引的全部内容了,后续还有MySQL索引的实现原理哦~~
本篇部分摘自大佬文章: