InnoDB索引

#################################### 索引 #################################
create database index_db;
use index_db;
# 创建索引 
create table t_citizen(
	id int primary key auto_increment,
    icard varchar(255) not null unique,
    name varchar(255) not null,
    age int,
    gender enum('female', 'male')
);

create index idx_name on t_citizen(name); 
alter table t_citizen add index idx_name (name);
# 查看索引 
show index from t_citizen;

# 删除索引
drop index idx_name on t_citizen;

# 回表思考下面SQL语句的执行过程:
select id from t_citizen where id = 1;  # 聚集索引 
select  id_card from t_citizen where id_card = '';  # 辅助索引
select name from t_citizen where id = 1; # 聚集索引
select name from t_citizen where id_card = ''; # 辅助索引 --> 聚集索引
select  * from t_citizen where id = 1; # 聚集索引 
select * from t_citizen where id_card = ''; # 辅助索引 --> 聚集索引

################################### explain #################################
# 语法:explain + select语句
use nba; 
explain select * from player;

# select_type: simple, primary, union, subquery, derived
# 1) simple
explain select * from player;
# 2) primary, union
use friend;
explain 
select * from boys
union 
select * from girls;
# 3) primary, subquery
use nba;
explain
select * from player where height = (
	select max(height) from player
);

# 4) primary, dependent subquery
explain
select * from player as a where height > (
	select avg(height) from player as b where b.team_id = a.team_id 
);

# 5) derived
explain
select * from player join (
	select team_id, avg(height) from player group by team_id
) as tmp using(team_id);

# type: null, system, const, eq_ref, ref, range, index, ALL
# null: 不需要查询表
explain select @@autocommit;

# system: 表中数据最多只有一行。
explain select * from (select 'xixi' as name, 16 as age) as tmp;

# const: 等值比较, 满足条件的记录最多有一条,并且和键比较的值是常数。
show index from player;
desc player;
select * from player;
explain select * from player where player_id = 10027;

# eq_ref: 等值比较, 满足条件的记录最多有一条,和键比较的值不是常数。
use index_db;
create table t_a(
	id int primary key,
    a int
);
create table t_b(
	id int primary key,
    b int
);
alter table t_a add column c int;
show index from t_a;
insert into t_a values (1, 1), (2, 2), (3, 3);
insert into t_b values (1, 1), (2, 2), (3, 3);
explain 
select * from t_a where a = (
	select b from t_b where t_b.id = t_a.id
);

# ref: 等值比较, 但是满足条件的记录可以有多条
create index idx_a on t_a(a);
explain select * from t_a where a = 1;

# range: 范围查询
explain select * from t_a where a between 1 and 2;

# index: 扫描辅助索引, 遍历辅助索引 
explain select a from t_a;

# ALL: 扫描聚集索引, 遍历聚集索引,全表扫描。
explain select * from t_a;

use index_db;
create table t (
    id int primary key auto_increment,
    a int,    
    b int,    
    c int,
    key idx_a_b (a, b)
); 

insert into t(a,b,c) values (1, 1,1), (1, 2,2), (2, 1,3), (2, 4,4), (3, 1,5), (3, 2,6);
show index from t;

show tables;
show index from t_citizen;
create index idx_name_age on t_citizen(name, age);
# 练习: 
explain select * from t_citizen where name = '' and age = 18; # idx_name_age, ref
explain select * from t_citizen where name = ''; # idx_name_age, ref
explain select * from t_citizen where age = 18; # PRIMARY, ALL
explain select * from t_citizen where name like 'ab%'; # idx_name_age, range
explain select * from t_citizen where name like '%ab'; # PRIMARY, ALL

# 练习:下面哪些SQL语句可以使用联合索引?
desc t;
show index from t;
explain select * from t where a = 1 and b = 2; # idx_a_b, ref
explain select * from t where a = 1; # idx_a_b, ref
explain select * from t where b = 2; # PRIMARY, ALL

create table buy_record (	
    id int primary key auto_increment,    
    user_id int not null,    
    buy_date date,
    money decimal(10,2)
);
create index idx_userId on buy_record(user_id);
create index idx_userId_date on buy_record(user_id,buy_date);
# 练习 
explain select * from buy_record where user_id = 1; # idx_userId, ref
explain select * from buy_record where user_id = 1 order by buy_date desc limit 3;
explain select * from buy_record force index(idx_userId) where user_id = 1 order by buy_date desc limit 3;

# 练习: 对于联合索引(a, b, c)下面哪些 SQL 可以利用联合索引直接得到结果,而不需要额外的排序操作?
show index from t;
drop index idx_a_b on t;
create index idx_a_b_c on t(a,b,c);
explain select * from t where a = 1 order by b; 
explain select * from t where a = 1 and b = 1 order by c;
explain select * from t where a = 1 order by c;

# 覆盖索引 
create table t1 (	
      id1 int,    
      id2 int,    
      a int,    
      b int,    
      c int,    
      d int,    
      primary key(id1, id2),    
      index idx_a_b(a, b)
);

insert into t1 values (1, 1, 10, 11, 12, 13), (1, 2, 20, 21, 22, 23), (2, 1, 30, 31, 32, 33), (2, 2, 40, 41, 42, 43);

# 思考:若主键为 (id1, id2), 辅助索引为 (a, b)。判断下面哪些 SQL 语句需要回表?
explain select b from t1 where a = 1; # (a,b) 不需要, ref
explain select a from t1 where b = 1; # (a,b) 不需要, index
explain select id2, b from t1 where a = 1; # (a, b) 不需要 ref
explain select id1, a from t1 where b = 1; # (a, b) 不需要 index

show index from buy_record;
explain select count(*) from buy_record; # idx_userId

# 练习:下面 SQL 哪些会使用全表扫描?哪些会用到索引?哪个索引?哪些会用到 file_sort ?
desc t1;
explain select count(*) from t1 group by a; # idx_a_b, index
explain select count(*) from t1 group by b; # idx_a_b, index, using file_sort
explain select count(*) from t1 group by id1; # PRIMARY, index
explain select count(*) from t1 group by id2; # idx_a_b, index, using file_sort
explain select count(*) from t1 group by c; # primary, ALL, using file_sort

######################### 什么时候该创建索引 ##########################
show tables;
select count(*) from user;
select count(*) from product_comment;
desc user;
desc product_comment;

# 1. 字段数值有唯一性限制 (MySQL自动创建了索引) 
# 2. 频繁作为where查询条件的字段, 尤其在数据表很大的情况下 
show index from user;
select * from user;
select * from user where user_name = 'user_9527'; #0.859s
create index idx_name on user(user_name);
select * from user where user_name = 'user_9527'; #0.000s

# 3. 需要经常排序和分组的字段 
show index from product_comment;
select comment_id from product_comment order by user_id; #0.469s
select count(*) from product_comment group by user_id; #?/?
create index idx_uid on product_comment(user_id);
select comment_id from product_comment order by user_id; #0.016s
select count(*) from product_comment group by user_id; #0.000

# 4. update, delete的where条件字段 
drop index idx_uid on product_comment;
delete from product_comment where user_id = 829818; #0.531
create index idx_uid on product_comment(user_id);
delete from product_comment where user_id = 829820; #0.000

# 5. distinct 字段需要创建索引 
drop index idx_uid on product_comment;
select distinct user_id from product_comment; #47.265s
create index idx_uid on product_comment(user_id);
select distinct user_id from product_comment; #0.016s

# 6. 多表连接的连接字段也应该创建索引 

################################### 什么时候不需要创建索引 #######################
# 1. 如果不在 where, group by, order by, distinct 中出现的字段,就没有必要创建索引 

# 2. 表的记录数太少 

# 3. 区分度不高的字段,我们没有必要创建索引(比如: 性别)
	# 特例:比如有个女儿国,女人数1000000,男人10. 之后我们要经常查询男人的信息,就可以创建索引。
    
# 4. 频繁更新的字段,不一定要创建索引。

################################## 索引失效的情况 ################################
# 1. 索引字段参与了计算 
show index from product_comment;
explain select * from product_comment where user_id + 1 = 829001; #0.375s
explain select * from product_comment where user_id = 829000; #0.000s

# 2. 对索引字段使用函数 
create index idx_text on product_comment(comment_text);
select * from product_comment where substr(comment_text, 1, 3) = 'abc'; #0.422
select * from product_comment where comment_text like 'abc%'; #0.078s

# 3. or查询 
explain select * from product_comment where user_id = 829001 or comment_text like 'abc%'; # 0
drop index idx_text on product_comment;
explain select * from product_comment where user_id = 829001 or comment_text like 'abc%';

#4. 模糊查询不能以%开头 
explain select * from product_comment where comment_text like 'abc%';
explain select * from product_comment where comment_text like '%abc';

#5.is not null 和 不等于 不会使用索引 
show index from product_comment;
explain select * from product_comment where user_id is not null;
explain select * from product_comment where user_id != 12345;

#6. 查找的范围太大,也会导致索引失效 
explain select * from product_comment where user_id between 10000 and 20000;
explain select * from product_comment where user_id between 10000 and 1000000;




猜你喜欢

转载自blog.csdn.net/weixin_41988545/article/details/106497091
今日推荐