一、索引是什么?
索引创建在表上,对数据库表中的一列或多列的值进行排列的一个结果。它是表中一列或多列值得集合和相应的指向表中物理标识这些值得数据页的逻辑指针清单。
优点:提高查询效率
缺点:过多的索引会导致CPU使用率降低
由于数据的改动会影响索引的改动,过多的索引会引起磁盘IO频繁造成CPU的负载太重
二、索引的种类
普通索引:没有任何限制条件,可以给任意类型的字段添加普通索引
唯一性索引:使用unique修饰的字段,值不能重复的,主键索引就隶属于唯一性索引
主键索引:使用primary key修饰的字段自动创建索引
单列索引:在一个字段上创建的索引
多列索引:在表的多个字段上创建的索引
全文索引:使用FULLTEXT参数可以设置全文索引,只支持char、varchar、text类型的字段上,常用于数据量比较大的字符创类型上,可以提高查询速度,只有MYISAM存储引擎支持
三、索引的创建和删除的SQL
1、创建表的时候创建索引
create table table_name(
id int,
name varchar,
index(id)
);
2、删除索引
drop index 索引名 on 表名;
3、在已经创建的表上添加索引
1.create [unique|fulltext|primary key|spatial]
index 索引名(idx_name) on 表名(属性名);
2. alter table 表名 add [unique|fulltext|primary key|spatial]
index 索引名(属性);
四、索引执行的过程
1.创建对应的表:Student
Student(SID,Sname,Sage,Ssex)
–SID 学生编号,Sname 学生姓名,Sage 年龄,Ssex 学生性别
2.添加数据
+-----+----------+------+------+
| SID | Sname | Ssex | Sage |
+-----+----------+------+------+
| 1 | zhaolei | nan | 20 |
| 2 | qiandian | nan | 20 |
| 3 | sunfen | nan | 21 |
| 4 | wulan | nv | 18 |
+-----+----------+------+------+
3.查询姓名为"zhaolei"的同学信息
select * from Student where Sname=‘zhaolei’;
mysql> explain select * from Student where Sname='zhaolei'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: Student
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: Using where
1 row in set (0.01 sec)
通过explain分析SQL的执行过程:possible_keys、key和执行过程中使用索引相关的字段,可以看到查询没命中索引。
rows: 4 表示是查询了4条数据,即进行了全表查询。当数据量比较大(400万),全表查询的效率是很低的。
给name字段添加索引
create index idx_name on Student(Sname);
mysql> explain select * from Student where Sname='zhaolei'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: Student
type: ref
possible_keys: idx_name
key: idx_name
key_len: 27
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
添加索引之后,再次查询"zhaolei"信息只在表中查询一行数据就可以得到了,而且可以看到:
当前执行命中的idx_name的索引的。
注意:explain命令:可以查看SQL的执行计划,分析SQL是否是正确使用索引
五、SQL和索引的优化原理
1、单表查询执行过程和执行优化-简单查询
查询sid=1的学生信息
explain select * from Student where SID = 1;
mysql> explain select * from Student where SID = 1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: Student
type: const
possible_keys: PRIMARY,SID
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
1 row in set (0.00 sec)
可以看到:possible_keys: PRIMARY,SID,在SQL执行过程用主键索引进行查找key: PRIMARY,在主键索引上一条数据就可以查到结果
通过name=‘zhaolei’;
explain select * from Student where Sname = ‘zhaolei’;
mysql> explain select * from Student where Sname = 'zhaolei'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: Student
type: ref
possible_keys: idx_name
key: idx_name
key_len: 27
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
where 后跟的是 Sname = ‘zhaolei’,分析能够通过索引idx_name辅助索引树找到name='zhaolei’对应的主键
,到主键索引上查询主键为1找到对应的一列数据返回
explain select SID from Student where Sname=‘zhaolei’;
mysql> explain select SID from Student where Sname='zhaolei'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: Student
type: ref
possible_keys: idx_name
key: idx_name
key_len: 27
ref: const
rows: 1
Extra: Using where; Using index
1 row in set (0.00 sec)
可以分析,where 后跟的是 Sname = ‘zhaolei’,分析能够通过索引idx_name辅助索引树找到name='zhaolei’对应的主键
,select 查询的是SID,在辅助索引就已经满足条件了,所以不需要在主键索引上再次查找
explain select Sage from Student where Sname=‘zhaolei’;
mysql> explain select Sage from Student where Sname='zhaolei'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: Student
type: ref
possible_keys: idx_name
key: idx_name
key_len: 27
ref: const
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
可以分析,where 后跟的是 Sname = ‘zhaolei’,分析能够通过索引idx_name辅助索引树找到name='zhaolei’对应的主键
,select 查询的是Sage,Sage对应在主键索引上,需要通过主键索引来获取到当前一列值中的Sage。
2、单表查询执行过程和执行优化-简单查询+排序或者分组
创建订单表:
orderlist();
userid 用户ID
productid 商品ID
date 时间;
create table order(
userid int not null,
productid int not null,
date datatime
);
| userid | productid | date |
+--------+-----------+---------------------+
| 1 | 1 | 2019-03-30 10:56:20 |
| 2 | 1 | 2019-03-30 14:56:20 |
| 1 | 2 | 2019-03-30 13:56:20 |
| 2 | 4 | 2019-03-30 12:56:20 |
| 1 | 5 | 2019-03-30 11:56:20 |
+--------+-----------+---------------------+
查询userID=1按照日期升序排序
select * from orderlist where userid=1 order by date;
同一个SQL查询过程中,只会命中一个索引
idx_id_date on orderlist(userid,date)|(date, userid);
eg:表 a\b都创建了索引
select * from test where a=1 and b= 1 and c=1;
select * from test where b=1 and c= 1 and a=1;
联合索引(a,b)
select * from test where b=1 ;
select * from test where a=1 ;
select * from test where a=1 and b = 1;
3、多表查询-连接查询的执行过程以及优化
创建两个表及其数据如下:
mysql> select * from Student;
+-----+----------+------+------+
| SID | Sname | Ssex | Sage |
+-----+----------+------+------+
| 1 | zhaolei | nan | 20 |
| 2 | qiandian | nan | 20 |
| 3 | sunfen | nan | 21 |
| 4 | wulan | nv | 18 |
+-----+----------+------+------+
4 rows in set (0.00 sec)
SC:
+------+------+-------+
| SID | CID | score |
+------+------+-------+
| 1 | 1 | 80 |
| 1 | 3 | 87 |
| 2 | 2 | 89 |
| 6 | 1 | 66 |
| 3 | 3 | 88 |
| 2 | 2 | 98 |
+------+------+-------+
联表查询
explain select * from Student a inner join SC b on a.SID=b.SID\G
mysql> explain select * from Student a inner join SC b on a.SID=b.SID\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: a
type: ALL
possible_keys: PRIMARY,SID 索引没有用上,进行全表搜索
key: NULL
key_len: NULL
ref: NULL
rows: 4
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: b 大表
type: ref
possible_keys: idx_id 命中索引,提高查询效率
key: idx_id
key_len: 5
ref: test.a.SID
rows: 1
Extra: NULL
2 rows in set (0.00 sec)
在使用多表进行联合查询时,MYSQL会首先判断那个表小,
表小指的是行数少,连接查询时:小表总是要整表搜索的,建索引是没有用的。
大表创建索引可以提高查询效率。小表决定了查询次数,大表决定了查询时间
查询score=88分的用户信息
explain select * from Student a inner join SC b on a.SID = b.SID where b.score = 88\G
select * from Student where SID in (select SID from SC);
六、索引优化总结
1、何时使用索引(每次查询只寻找一个索引)
(1)主键,unique字段;
(2)和其他表做连接的字段需要加索引
(3)在where里使用>,≥,=,<,≤,is null和between等字段;
(4)使用不以通配符开始的like,where A like ‘China%’;
(5)聚集函数MIN(),MAX()中的字段;
(6)order by和group by字段;
2、何时不使用索引
(1)表记录太少;
(2)数据重复且分布平均的字段(只有很少数据值的列);
(3)经常插入、删除、修改的表要减少索引;
(4)text,image等类型不应该建立索引,这些列的数据量大(假如text前10个字符唯一,也可以对text前10个字符建立引);
(5)MySQL能估计出全表扫描比使用索引更快时,不使用索引;
3、索引何时失效
(1)组合索引未使用最左前缀,例如组合索引(A,B),where B=b不会使用索引;
(2)like未使用最左前缀,where A like ‘%China’;
(3)搜索一个索引而在另一个索引上做order by,where A=a order by B,只使用A上的索引,因为查询只使用一个索引 ;
(4)or会使索引失效。如果查询字段相同,也可以使用索引。例如where A=a1 or A=a2(生效),where A=a or B=b(失效)
(5)如果列类型是字符串,要使用引号。例如where A=‘China’,否则索引失效(会进行类型转换);
(6)在索引列上的操作,函数(upper()等)、or、!=(<>)、not in等;
4.SQL 语句的优化
1)利用慢查询日志找出响应较慢的SQL语句
2)explain语句查看这些较慢语句的执行计划(包括可能用到的索引和真正使用的索引)
3)利用like“%”查询找出冗余索引,对其进行分析优化 4)拆分大表,增加中间表(依赖三大范式) 第一范式:字段不可分割。
第二范式:所有字段不能依赖于非主属性 第三范式:所有字段必须依赖于主键列
2.MySQL Server服务器的参数进行优化(可以配置服务器线程的数量, 查询缓存)
3.对应用的优化
a.减少和MySQL Server建立连接和断开链接的额外消耗,引入连接池
b.减少MySQL Server的磁盘I/O操作,利用redis和memcached缓存机制