一、索引的声明与使用
mysql的索引包括普通、唯一性、全文、单列、多列和空间索引
-从功能逻辑:普通、唯一、主键和全文索引
-从物理实现上:聚簇和非聚簇索引
-从作用字段个数上:单列和联合索引

普通索引:可以创建在任何数据类型中,查询记录时就可以根据该索引进行查询
唯一性索引:使用unique参数可以设置唯一性索引,在创建唯一性索引时,限制索引的值必须是唯一的,但允许为空值,一张表可以有多个唯一性索引
主键性索引:最多有一个主键,也叫做聚簇索引、
单列索引:就是单个字段上创建的索引
多列索引:多个字段上创建的索引,也叫做组合或者联合索引或者非聚簇索引,同时遵循最左前缀集合

二、索引的创建
查看索引
show create table book;
show index from book;
第一种在创建表的同时创建索引
1、普通索引
index idx_bname(book_name)
index:创建标识
idx_bname:索引名称
book_name:字段名称
2、创建唯一索引

unique index uk_idx_cmt(comment)


3、通过定义主键约束的方式定义主键索引(隐式的)
删除:alter table book2 drop primary key
4、单列索引
一个字段的索引
5、联合索引

index mul_bid_name_info(book_id, book_name, info)


6、全文索引

fulltext index futxt_idx_info(info(50))


全文索引用match+against查询:
select * from papers where match(title, content) against(‘查询字符串’);
7、创建空间索引
spatial index spa_idx_geo(geo)
第二种,表已经创建好

1、alter table … add …
 alter table book5 add index idx_cmt(comment);
 alter table book5 add unique index idx_cmt(comment);
 alter table book5 add index idx_cmt(id, comment, title);
 2、create index … on …
 create index idx_cmt on book6(comment);

三、索引的删除

1、alter table … drop …
 alter table book5 drop index idx_cmt;
 alter table book5 drop unique index idx_cmt;
 2、drop index … on …
 drop index idx_cmt on book6;

四、索引的新特性(8.0)
1、降序索引
alter table book5 add index idx_cmt(a, b desc);
2、隐藏索引
通过先将索引设置为隐藏索引,再删除索引的方式就是软删除
建表以后:
1、alter table … add … invisible
alter table book5 add unique index idx_cmt(comment) invisible;
默认为:visible-可见,invisible-不可见
1、create index … on … invisible

五、索引的设计原则
1、数据准备
第一步:创建数据库,创建表

create database atguigudb1;
 use atguigudb1;
 #1创建学生表和课程表
 create table student_info (
id int(11) not null auto_increment,
student_id int not null,
name varchar(20) default null,
course_id int not null,
class_id int(11) default null,
create_time datetime default current_timestamp on update current_timestamp,
 primary key(id)
 ) engine=innodb auto_increment=1 default charset=utf8;create table course (
id int(11) not null auto_increment,
course_id int not null,
course_name varchar(40) default null,
 primary key(id)
 ) engine=innodb auto_increment=1 default charset=utf8;

第二步:创建模拟数据必需的存储函数

1:创建随机产生字符串函数

DELIMITER //
 CREATE FUNCTION rand_string(n INT)
 RETURNS VARCHAR(255) #该函数会返回一个字符串
 BEGIN
 DECLARE chars_str VARCHAR(100) DEFAULT ‘abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ’;
 DECLARE return_str VARCHAR(255) DEFAULT ‘’;
 DECLARE i INT DEFAULT 0;
 WHILE i < n DO
 SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
 SET i = i + 1;
 END WHILE;
 RETURN return_str;
 END //
 DELIMITER ;SELECT @@log_bin_trust_function_creators;
 SET GLOBAL log_bin_trust_function_creators = 1;

#函数2:创建随机数函数

DELIMITER //
 CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
 BEGIN
 DECLARE i INT DEFAULT 0;
 SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ;
 RETURN i;
 END //
 DELIMITER ;

存储过程1:创建插入课程表存储过程

DELIMITER //
 CREATE PROCEDURE insert_course( max_num INT )
 BEGIN
 DECLARE i INT DEFAULT 0;
 SET autocommit = 0; #设置手动提交事务
 REPEAT #循环
 SET i = i + 1; #赋值
 INSERT INTO course (course_id, course_name ) VALUES (rand_num(10000,10100),rand_string(6));
 UNTIL i = max_num
 END REPEAT;
 COMMIT; #提交事务
 END //
 DELIMITER ;

存储过程2:创建插入学生信息表存储过程

DELIMITER //
 CREATE PROCEDURE insert_stu( max_num INT )
 BEGIN
 DECLARE i INT DEFAULT 0;
 SET autocommit = 0; #设置手动提交事务
 REPEAT #循环
 SET i = i + 1; #赋值
 INSERT INTO student_info (course_id, class_id ,student_id ,NAME ) VALUES (rand_num(10000,10100),rand_num(10000,10200),rand_num(1,200000),rand_string(6));
 UNTIL i = max_num
 END REPEAT;
 COMMIT; #提交事务
 END //
 DELIMITER ;

#调用存储过程:

CALL insert_course(100);
 SELECT COUNT() FROM course;
 CALL insert_stu(1000000);
 SELECT COUNT() FROM student_info;

那些情况适合创建索引
1、字段的数值有唯一性的限制
2、频繁作为where查询条件的字段
3、经常group by和order by的列
4、udpate,delete的where条件列
5、distinct字段需要创建索引
6、多表join连接操作时,创建索引注意事项
-连接表的数量尽量不要超过3张
-对where条件创建索引
-对用于连接的字段创建索引
7、使用列的类型小的创建索引
8、使用字符串前缀创建索引
9、区分度高的列适合作为索引
10、使用最频繁的列放到联合索引的左侧
11、多个字段都要创建索引联合索引优于单值索引
限制索引的数目
单表不超过6个,原因如下:
1、每个索引都要占用磁盘空间,索引多,占用空间大
2、索引会影响insert、delete、update等语句,索引的调整和更新会有负担
3、优化器在选择如何优化查询时,会对每一个用到的索引进行评估,以便找到最好的执行计划,会增加生成执行计划时间,降低查询性能

那些情况不适合创建索引
在where中使用不到的字段,不要设置索引
数据量小的表最好不要使用索引
大量重复数据的列不要建立索引
避免对经常更新的表创建过多的索引
不建议用无序的值作为索引
删除不再使用或者很少使用的索引
不要定义冗余或重复的索引

索引优化与查询优化
#建库

CREATE DATABASE atguigudb2;


#建表

CREATE TABLE class (
id INT(11) NOT NULL AUTO_INCREMENT,
className VARCHAR(30) DEFAULT NULL,
address VARCHAR(40) DEFAULT NULL,
monitor INT NULL ,
 PRIMARY KEY (id)
 ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE TABLE student (
id INT(11) NOT NULL AUTO_INCREMENT,
stuno INT NOT NULL ,
name VARCHAR(20) DEFAULT NULL,
age INT(3) DEFAULT NULL,
classId INT(11) DEFAULT NULL,
 PRIMARY KEY (id)
 #CONSTRAINT fk_class_id FOREIGN KEY (classId) REFERENCES t_class (id)
 ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;SET GLOBAL log_bin_trust_function_creators=1;

#随机产生字符串

DELIMITER //
 CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
 BEGIN
 DECLARE chars_str VARCHAR(100) DEFAULT ‘abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ’;
 DECLARE return_str VARCHAR(255) DEFAULT ‘’;
 DECLARE i INT DEFAULT 0;
 WHILE i < n DO
 SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
 SET i = i + 1;
 END WHILE;
 RETURN return_str;
 END //
 DELIMITER ;

#用于随机产生多少到多少的编号

DELIMITER //
 CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
 BEGIN
 DECLARE i INT DEFAULT 0;
 SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ;
 RETURN i;
 END //
 DELIMITER ;

#创建往stu表中插入数据的存储过程

DELIMITER //
 CREATE PROCEDURE insert_stu( START INT , max_num INT )
 BEGIN
 DECLARE i INT DEFAULT 0;
 SET autocommit = 0; #设置手动提交事务
 REPEAT #循环
 SET i = i + 1; #赋值
 INSERT INTO student (stuno, NAME ,age ,classId ) VALUES ((START+i),rand_string(6),rand_num(1,50),rand_num(1,1000));
 UNTIL i = max_num
 END REPEAT;
 COMMIT; #提交事务
 END //
 DELIMITER ;

#执行存储过程,往class表添加随机数据

DELIMITER //
 CREATE PROCEDURE insert_class( max_num INT )
 BEGIN
 DECLARE i INT DEFAULT 0;
 SET autocommit = 0;
 REPEAT
 SET i = i + 1;
 INSERT INTO class ( classname,address,monitor ) VALUES (rand_string(8),rand_string(10),rand_num(1,100000));
 UNTIL i = max_num
 END REPEAT;
 COMMIT;
 END //
 DELIMITER ;#执行存储过程,往class表添加1万条数据
 CALL insert_class(10000);
 #执行存储过程,往stu表添加50万条数据
 CALL insert_stu(100000,500000);SELECT COUNT() FROM class;
 SELECT COUNT() FROM student;

#删除表中指定索引

DELIMITER //
 CREATE PROCEDURE proc_drop_index(dbname VARCHAR(200),tablename VARCHAR(200))
 BEGIN
 DECLARE done INT DEFAULT 0;
 DECLARE ct INT DEFAULT 0;
 DECLARE _index VARCHAR(200) DEFAULT ‘’;
 DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>‘PRIMARY’ ;


#每个游标必须使用不同的declare continue handler for not found set done=1来控制游标的结束
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=2 ;
#若没有数据返回,程序继续,并将变量done设为2

OPEN _cur;
 FETCH _cur INTO _index;
 WHILE _index<>‘’ DO
 SET @str = CONCAT("drop index " , _index , " on " , tablename );
 PREPARE sql_str FROM @str ;
 EXECUTE sql_str;
 DEALLOCATE PREPARE sql_str;
 SET _index=‘’;
 FETCH _cur INTO _index;
 END WHILE;
 CLOSE _cur;
 END //
 DELIMITER ;

覆盖索引的利弊
好处:
避免Innodb表进行索引的二次查询(回表)
可以把随机IO变成顺序IO加快查询效率:由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段
弊端:索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。

索引下推
好处:ICP可以减少存储引擎必须访问基表的次数和MySQL服务器必须访问存储引擎次数
但是,ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例
默认情况下启用索引条件下推。当使用索引条件下推时,EXPLAIN语句输出结果中Extra列内容显示为Using index condition