前言
不管在学习数据库或者在面试时都会遇到索引这个玩意儿,是我们走向光头必不可少的一项技能!对于数据库如何优化,都会想到加索引,我们就来说说到底什么是索引,怎么用,如何用好等!索引数据结构请戳《搞懂MySQL数据库索引数据结构这一篇足够从此不再萌萌哒》,话不多说直接开搞!
索引你做个自我介绍
各位看客老爷我是索引,我其实很简单不像外边的妖艳贱货那么复杂,官网上说人家是存储引擎用于快速找到记录的一种数据结构,不通的存储引擎对索引的实现方式不同,一般存储在磁盘中,为了减少数据扫描的次数,将随机I/O转变为顺序I/O,帮助我们在分组、排序等操作时,避免使用临时表。比如新华字典,要去找一个字可以通过翻目录用偏旁,拼音等来找一个字,如果没有这个目录你就得一页一页去找,索引就是数据库性能调优的基础方式,常用于实现数据的快速检索,接下来我要给大家好好介绍一下索引。
MySql数据访问方式
在Mysql中通常有以下两种方式来检索一行数据,如以下数据表
id | name | age |
1 | 石添添 | 18 |
2 | 石小添 | 19 |
3 | 石笑天 | 10 |
4 | 石小索 | 15 |
5 | 石小引 | 21 |
6 | 石以初 | 20 |
顺序访问
顺序访问是执行全表扫描,比如我们要检索age为15的用户,从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。这种方式实现比较简单,但是当表中有大量数据的时候,效率非常低下。例如,在几千万条数据中查找少量的数据时,使用顺序访问方式将会遍历所有的数据,花费大量的时间,显然会影响数据库的处理性能!
索引访问
索引访问是通过遍历索引来直接访问表中记录行的方式。使用这种方式的前提是对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。
例如:我们在age列上添加索引,数据库系统就建立了一张索引列到实际记录的映射表,当需要查找age为15的数据时,会先在age索引上找到该记录,然后通过映射表直接找到数据行,并且返回该行数据。因为扫描索引的速度一般远远大于扫描实际数据行的速度,所以采用索引的方式可以大大提高数据库的工作效率。
至此我们知道索引是一种数据结构,需要单独存放可以增快我们的查询效率,是数据库优化的一种基础而重要方案,数据库搜索数据顺序访问和索引访问两种方式。
索引创建
MySql提供三种创建索引的方法,注意InnoDB引擎会自动在主键上添加索引
使用CREATE INDEX 语句
用于在表已存在添加索引
语法
CREATE INDEX <索引名> ON <表名> (<列名> [<长度>] [ ASC | DESC])
说明
- 索引名:指定索引名。一个表可以创建多个索引,但每个索引名在表中唯一
- 表名:指定在哪个表中创建索引
- 列名:指定要创建索引的列名。通常可以考虑将查询语句中在 JOIN 子句和 WHERE 子句里经常出现的列作为索引列,可以是一列也可以是多列,一列的称之为单列索引,多列成为组合索引
- 长度:可选项。指定使用列前的 length 个字符来创建索引。使用列的一部分创建索引有利于减小索引文件的大小,节省索引列所占的空间。在某些情况下,只能对列的前缀进行索引。索引列的长度有一个最大上限 255 个字节(MyISAM 和 InnoDB 表的最大上限为 1000 个字节),如果索引列的长度超过了这个上限,就只能用列的前缀进行索引。另外,BLOB 或 TEXT 类型的列也必须使用前缀索引
- ASC | DESC:可选项。ASC指定索引按照升序来排列,DNSC指定索引按照降序来排列,默认为ASC
例子
CREATE INDEX index_user_age ON tb_user(age);
使用CREATE TABLE 语句
用于在创建表(CREATE TABLE)时创建,在CREATE TABLE 语句下添加
语法
1、表示在创建新表的同时创建该表的索引
KEY | INDEX [<索引名>] [<索引类型>] (<列名>,…)
2、表示在创建新表的同时创建该表的唯一性索引
UNIQUE [ INDEX | KEY] [<索引名>] [<索引类型>] (<列名>,…)
例子
CREATE TABLE student(
id INT PRIMARY KEY,
`name` VARCHAR(10) NOT NULL,
class VARCHAR(10) NOT NULL,
INDEX(name) -- 在name列上创建索引
);
使用 ALTER TABLE 语句
在使用 ALTER TABLE 语句修改表的同时,可以向已有的表添加索引。具体的做法是在 ALTER TABLE 语句中添加以下语法成分的某一项或几项
语法
1、在修改表的同时为该表添加索引
ADD INDEX [<索引名>] [<索引类型>] (<列名>,…)
2、在修改表的同时为该表添加唯一性索引
ADD UNIQUE [ INDEX | KEY] [<索引名>] [<索引类型>] (<列名>,…)
例子
ALTER TABLE student ADD INDEX index_class (class);
查看索引
语句
SHOW INDEX FROM <表名> [ FROM <数据库名>]
例子
SHOW index FROM table_name;
说明
- 表名:查询索引的表名
- 数据库名:要查询的表在哪个数据库,这个可以使用数据库名.表名替代
- Table:表名
- No_unique:用于显示该索引是否是唯一索引。若不是唯一索引,则该列的值显示为 1;若是唯一索引,则该列的值显示为 0
- Key_name:索引的名称,不指定名称就是列名
- Seq_in_index:索引中的列序列号,从1开始计数
- Column_name:列名
- Collation:显示列以何种顺序存储在索引中。在 MySQL 中,升序显示值“A”,若显示为 NULL,则表示无分类
- Cardinality:显示索引中唯一值数目的估计值。基数根据被存储为整数的统计数据计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL 使用该索引的机会就越大
- Sub_part:若列只是被部分编入索引,则为被编入索引的字符的数目。若整列被编入索引,则为 NULL
- Packed:指示关键字如何被压缩。若没有被压缩,则为 NULL
- Null:用于显示索引列中是否包含 NULL。若列含有 NULL,则显示为 YES
- Index_type:显示索引使用的类型和方法(BTREE、FULLTEXT、HASH、RTREE)
- Comment:显示评注
- Index_comment:显示评注
删除索引
当老板不再用我的时候,可以使用 DROP INDEX 语句或 ALTER TABLE 语句来删除我!
删除
语法
DROP INDEX <索引名> ON <表名>
或者再ALTER TABLE语句后边添加
DROP INDEX index_name:表示删除名称为 index_name 的索引。
注意:如果删除的列是索引的组成部分,那么在删除该列时,也会将该列从索引中删除;如果组成索引的所有列都被删除,那么整个索引将被删除
例子
DROP INDEX name ON student;
或
ALTER TABLE student DROP INDEX index_class;
索引分类
根据索引的用途在逻辑上可以分为以下五种
普通索引
普通索引是最基本的索引类型,唯一任务是加快对数据的访问速度,没有任何限制。创建普通索引时,通常使用的关键字是 INDEX 或 KEY
唯一性索引
唯一性索引是不允许索引列具有相同索引值的索引。如果能确定某个数据列只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字 UNIQUE 把它定义为一个唯一性索引。创建唯一性索引的目的往往不是为了提高访问速度,而是为了避免数据出现重复
主键索引
主键索引是一种唯一性索引,即不允许值重复或者值为空,并且每个表只能有一个主键。主键可以在创建表的时候指定,也可以通过修改表的方式添加,必须指定关键字 PRIMARY KEY,注意一张表只能有一个主键
空间索引
空间索引主要用于地理空间数据类型 GEOMETRY
全文索引
全文索引只能在 VARCHAR 或 TEXT 类型的列上创建,并且只能在 MyISAM
在实际使用中,索引通常被创建成单列索引和组合索引
- 单列索引就是索引只包含原表的一个列
- 组合索引也称为复合索引或多列索引,相对于单列索引来说,组合索引是将原表的多个列共同组成一个索引
敲黑板:一个表可以有多个单列索引,但这些索引不是组合索引。一个组合索引实质上为表的查询提供了多个索引,以此来加快查询速度。比如,在一个表中创建了一个组合索引(c1,c2,c3),在实际查询中,系统用来实际加速的索引有三个:单个索引(c1)、双列索引(c1,c2)和多列索引(c1,c2,c3)
索引注意事项和使用原则
注意事项
创建索引虽然可以提升Mysql的查询性能,但是索引在使用的时候也不是为所欲为,越多越好,需要注意以下几点
- 索引的创建和维护需要消耗时间,这个时间会随着数据量的增多而增加
- 除了表中数据占用控件,索引也需要占用一定空间,如果要建立聚簇索引,那么需要的空间就会更大
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度
使用原则
- 在经常需要搜索的列上建立索引,可以加快搜索的速度
- 在作为主键的列上创建索引,强制该列的唯一性,并组织表中数据的排列结构,在InnoDB存储引擎,默认给主键添加索引
- 在经常使用表连接的列上创建索引,这些列主要是一些外键,可以加快表连接的速度
- 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,所以其指定的范围是连续的
- 在经常需要排序的列上创建索引,因为索引已经排序,所以查询时可以利用索引的排序,加快排序查询
- 在经常出现在WHERE子句中的列上添加索引,加快条件的判断速度
以下场景建议不要添加索引,添加了反而增加数据库的压力,产生负面影响
- 对于那些在查询中很少使用或参考的列不应该创建索引。因为这些列很少使用到,所以有索引或者无索引并不能提高查询速度。相反,由于增加了索引,反而系统要去维护和存储,增大压力
- 对于那些只有很少数据值的列也不应该创建索引。因为这些列的取值很少,例如用户表的爱好列。查询结果集的数据行占了表中数据行的很大比例,增加索引并不能明显加快检索速度
- 对于那些定义为 TEXT、IMAGE 和 BIT 数据类型的列不应该创建索引。因为这些列的数据量要么相当大,要么取值很少
- 当修改性能远远大于检索性能时,不应该创建索引。因为修改性能和检索性能是互相矛盾的。当创建索引时,会提高检索性能,降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引,就是表中某个字段经常修改不要添加索引,因为会动态维护!