一、概要
索引就像一本书的目录。而当用户通过索引查找数据时,就好比用户通过目录查询某章节的某个知识点。这样就帮助用户有效地提高了查找速度。所以,使用索引可以有效地提高数据库系统的整体性能
在我们的一个应用系统中,读写的比例一般大概8:2左右,在实战开发中,当数据量比较大的时候查询的速度比较慢的时候,我们可以通过创建索引的方式来加快我们的查询速度
二、什么叫索引
系统根据某种算法,将已有的数据(未来可能新增的数据),单独建立一个文件,这个文件能够实现快速匹配数据,并且能够快速的找到对应的记录,本质上是一种数据结构
三、优缺点
1、优点
- 提升查询数据的效率
- 可以加速表与表之间的连接
- 在使用分组和排序进行检索的时候,可以减少查询中分组和排序的时间
2、缺点
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
- 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
- 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
三、索引分类
1、按存储结构
- BTree索引
- Hash索引
- 位图索引(mysql不支持)
2 、按应用层次
- 普通索引,
- 主键索引
- 唯一索引
- 全文索引
- 复合索引
3、数据行的物理顺序与列值的逻辑顺序相同
- 聚集索引
- 非聚集索引
四、基本使用
4.1、主键索引
-
说明
创建主键约束自动会建立主键索引,不允许重复,不允许空值;
-
语法格式
-- 创建主键时数据库自动创建 CREATE TABLE 表名 ( 列名 类型 PRIMARY KEY ) -- 或者 表级创建 CREATE TABLE 表名 ( 列名 类型 , PRIMARY KEY(列名) )
-
示例代码
CREATE TABLE t_test( -- 自动创建主键索引 tid int AUTO_INCREMENT PRIMARY KEY ) -- 或者 CREATE TABLE t_test( -- 自动创建主键索引 tid int AUTO_INCREMENT , PRIMARY KEY(tid) )
4.2、普通索引
-
说明
在创建普通索引时,不附加任何限制条件。这类索引可以创建在任何数据类型中,其值是否唯一和非空由字段本身的完整性约束条件决定。
-
语法格式
-- 在创建表的时候创建 (不推荐) CREATE TABLE 表名( 列名 类型 约束, ...., key () ) -- 创建表之后在创建索引 (推荐方式创建) CREATE INDEX 索引名 ON 表 (列名,);
-
示例代码
CREATE TABLE t_index_key ( tid int PRIMARY KEY AUTO_INCREMENT, name varchar(64) NOT NULL, KEY (name) )
-- 删除索引 DROP INDEX name ON t_index_key -- 创建索引 推荐 CREATE INDEX idx_key_name ON t_index_key(name) -- 查看索引 EXPLAIN SELECT * from t_index_key WHERE name='123'
4.3、唯一索引
-
说明
用来建立索引的列的值必须是唯一的,允许空值, 可以通过创建表的时候使用唯一约束创建
-
语法格式
CREATE UNIQUE INDEX 索引名 ON 表名(列名 DESC,列名)
-
示例代码
CREATE UNIQUE INDEX idx_user_username ON t_user(username DESC)
4.4、全文索引
-
说明
即为全文索引,Mysql5.6之前只有MyISAM引擎支持,Mysql5.6之后InnoDB也支持。目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引
主要解决 它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题
-
创建格式
-- 1. 创建表 DROP TABLE IF EXISTS t_myisam; CREATE TABLE t_myisam ( mid int AUTO_INCREMENT PRIMARY KEY, name varchar(64) NOT NULL, detail text ) ENGINE = MYISAM DEFAULT CHARSET = UTF8MB4;
-
查询格式
MATCH (列名,...) AGAINST ('查询的关键字')
-
示例代码
-- 1. 创建 DROP TABLE IF EXISTS t_myisam; CREATE TABLE t_myisam ( mid int AUTO_INCREMENT PRIMARY KEY, name varchar(64) NOT NULL, detail text ) ENGINE = MYISAM DEFAULT CHARSET = UTF8MB4; -- 2.创建全文索引 CREATE FULLTEXT INDEX idx_username_detail ON t_myisam(detail) -- 查看索引信息 SHOW INDEX FROM t_myisam -- 或者 SHOW KEYS FROM t_myisam SELECT * FROM t_myisam WHERE MATCH(detail) AGAINST('%ab%') -- 查看索引是否生效 EXPLAIN SELECT * FROM t_myisam WHERE MATCH(detail) AGAINST('%ab%')
4.5、联合索引(多列索引)
-
说明
联合索引遵守“最左前缀”原则,即在查询条件中使用了联合索引的第一个字段,索引才会被使用。因此,在联合索引中索引列的顺序至关重要。如果不是按照索引的最左列开始查找,则无法使用索引
-
语法格式
CREATE INDEX 索引名 ON 表名(索引字段,索引字段,...)
-
示例代码
CREATE TABLE t_user ( uid int AUTO_INCREMENT PRIMARY KEY, username varchar(64) NOT NULL, password varchar(128) NOT NULL, phone varchar(11) NOT NULL, is_delete tinyint DEFAULT 0 NOT NULL, create_date timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT index_user_name UNIQUE (username) ); -- 创建普通的联合索引 CREATE INDEX index_user_date ON t_user (username,phone,create_date);
-- 联合索引字段 username,phone,create_date -- 1. 可以 SELECT * FROM t_user WHERE username = 'admin'; -- 2. 可以 SELECT * FROM t_user WHERE username = 'admin' AND phone = '123456'; -- 3. 可以 SELECT * FROM t_user WHERE username = 'admin' AND phone = '123456' AND create_date = '2019-07-18 17:04:12'; -- 不可以 SELECT * FROM t_user WHERE phone = '123456';
-
最左前缀的原则
- 如果我们建立了一个2列的联合索引(a,b),实际上已经相当于建立了两个联合索引( a ) 、( a, b );
- 如果有一个3列索引( a, b, c ),实际上已经建立了三个联合索引( a )、(a, b)、(a, b, c)。依次内推
-
总结
当创建(a,b,c)联合索引时,相当于创建了(a)单列索引,(a,b)联合索引以及(a,b,c)联合索引
想要索引生效的话,只能使用 a和a,b和a,b,c三种组合;当然,测试过,a,c组合也可以
五、什么情况使用索引
- 索引应该经常建在where 子句经常用到的列上。如果某个大表经常使用某个字段进行查询,并且检索行数小于总表行数的5%。则应该考虑。
- 对于两表连接的字段,应该建立索引。如果经常在某表的一个字段进行Order By 则也经过进行索引。
- 不应该在小表上建设索引(例如表中只有三四个字段)。
六、索引失效的情况
-
对索引列运算,运算包括(+、-、*、/、!、%),导致索引失效
-- 则会使索引失效, EXPLAIN SELECT * FROM tbl WHERE age + 5 > 10
-
不等于(!=)比较特殊 除主键索引或索引是整数类型外的其它索引都失效
EXPLAIN SELECT * FROM t_user WHERE username != 'OlUldQDIVV'; -- 索引有效 EXPLAIN SELECT * FROM t_user WHERE uid != 1;
like以通配符开头(‘%’),如果非要用使用全文索引
如果条件中有or,即使其中有条件带索引也不会使用 如果想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
小于 大于这个根据实际查询数据来判断,如果全盘扫描速度比索引速度要快则不走索引 。
-
索引列上不要使用函数,oracle必须使用函数索引
-- 索引失效 SELECT * FROM t_user WHERE substr(username ,1 ,3 ) = 'ABC'
总结一句话就是, 使用explain 关键执行一下 key是否有值, 有值就说明走了索引,null就表示索引失效
七、key和index区别
1、说明
key 是数据库的物理结构,它包含两层意义,一是约束(偏重于约束和规范数据库的结构完整性),二是索引(辅助查询用的)。包括primary key, unique key, foreign key
2、primary key
- 一是约束作用(constraint),用来规范一个存储主键和唯一性,
- 同时也在此key上建立了一个index
3、 unique key
- 约束作用(constraint),规范数据的唯一性
- 在这个key上建立了一个index
4、foreign key
- 约束作用(constraint),规范数据的引用完整性
- 在这个key上建立了一个index
七、总结
- 能用唯一索引,一定用唯一索引
- 可以给字段加非空约束就尽量加上非空约束
- 联合索引的顺序不同,影响索引的选择,尽量将值少的放在前面
- 千万不要给大字段加索引
八 、其它
1、查看索引
-
语法
show index from tblname; -- 或者 show keys from tblname;
-
说明
- Non_unique:如果索引不能包括重复词,则为0。如果可以,则为1
- Key_name:索引的名称
- Column_name:索引列名称
- Index_type :索引类型