面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句

1.什么是索引的最左前缀

如下图即为索引的左前缀,简单来说,我们创建的一个索引,这个索引中有多个字段,那么我们在使用这个索引时应遵循从左到右顺序使用,如上图的a,b,c字段,我们在使用是应为先a到b再到c的顺序,如果我们跳过了a,则整个索引将失效,如果我们想从a一步飞到c,那c将失效,因为我们跳过了b,并且在使用索引时应避免出现大于或小于等的范围,这会使后面的索引失效,在索引中也是可以使用like关键字的,但前提是%不能出现在查找字的前面,否则,此字段将变为范围,导致后面的索引失效

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第1张图片

2.创建实验所需的表

数据库表
CREATE TABLE `dept`(
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`deptName` VARCHAR(30) DEFAULT NULL,
	`address` VARCHAR(40) DEFAULT NULL,
	ceo INT NULL,
	PRIMARY KEY(`id`)
)ENGINE=INNODB AUTO_INCREMENT=1;

CREATE TABLE `emp`(
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`empno` INT NOT NULL,
	`name` VARCHAR(20) DEFAULT NULL,
	`age` INT(3) DEFAULT NULL,
	`deptId` INT(11) DEFAULT NULL,
	PRIMARY KEY(`id`)
)ENGINE=INNODB AUTO_INCREMENT=1;

创建函数

查看mysq1是否允许创建函数
SHOW VARIABLES LIKE 'log_bin_function_creators';
命令开启,允许创建函数设置: (global-所有session都生效)
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 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
   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 $$
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 $$
CREATE PROCEDURE insert_emp(START INT,max_num INT)
BEGIN
   DECLARE i INT DEFAULT 0;
   SET autocommit = 0;
   REPEAT
	SET i = i+1;
	INSERT INTO emp(empno,NAME,age,deptId) VALUES((START+i),rand_string(6),rand_num(30,50),rand_num(1,10000));
	UNTIL i = max_num
	END REPEAT;
	COMMIT;
END $$
插入部门数据
DELIMITER $$
CREATE PROCEDURE insert_dept(max_num INT)
BEGIN
   DECLARE i INT DEFAULT 0;
   REPEAT
	SET i = i+1;
	INSERT INTO dept(deptName,address,ceo) VALUES(rand_string(8),rand_string(10),rand_num(1,500000));
	UNTIL i = max_num
   END REPEAT;
   COMMIT;
END $$

调用存储过程

执行存储过程,在emp表添加50万条数据,编号从100000开始
call insert_emp(100000,500000);
执行存储过程,往dept表添加1万条数据
call insert_dept(100000);

因为我们要测索引,所以批量删除无用的索引

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=2;
   OPEN _cur;
	FETCH _cur INTO _index;
	WHILE _index<>''DO
	   SET @str = CONCAT("drop index ",_index," on ",tablename );
	   PREPARE sq1_str FROM @str ;
	   EXECUTE sq1_str;
	   DEALLOCATE PREPARE sql_str;
	   SET _index='';
	   FETCH _cur INTO _index;
	END WHILE;
   CLOSE _cur;
END $$

interview是库名,dept是表名,记得改
CALL proc_drop_index("interview","dept");

3.具体实验

我们接下来就对这个emp这个表进行操作,给他创建一个索引
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
查看是否有索引
SHOW INDEX FROM emp;

有下图为前面的成功了

我们接下来就调用索引测试一下吧,通过前面最左前缀所说的,下面的这一个所以应该就会成功

EXPLAIN SELECT * FROM emp ORDER BY age,deptid;

但运行后发现他竟然是全查找,这代表我们的索引失效了,为什么呢?

这就引出了个很重要的关键点,即为无过滤不索引,因为我们没有where条件,所以它所以自然就失效了,所以当我们在下图加上where后索引就成功使用了

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第2张图片

那我们把这个age改成范围呢?结果发现,他虽然用到了索引,但是他竟然是全扫描,这就代表了他不仅仅使用了索引,因为我们使用了*号,所以他会通过需要回表去查询所需的数据,所以在使用缩阴的时候,尽量避免出现范围

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第3张图片

我们把*号改成我们对应的字段后类型就变成了range,这个是连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况,所以会比ref差,所以在使用索引的时候,尽量避免出现范围

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第4张图片

根据我们前面所说的最左前缀法则,我们试着把age删掉,让它不符合条件,接下来我们就发现它会出现一个Using filesort,这是个很严重的错误,代表我们的索引要优化了,这就是order by非最左 filesort

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第5张图片

下图这两个分别为顺序错误和中间跳过,这些都会报这个错误,所以使用时要遵循自己定义索引的顺序来排面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第6张图片

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第7张图片

接下来我们来看看对这个字段进行排序会怎么样,我现在是全都是为倒序来排序,发现他索引是能够正常使用的

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第8张图片

那我们反骨的对其中一个的顺序进行更改呢?结果发现报filesort了,所以我们在进行排序的时候,也要保持一致的方向,方向反就会报filesort

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第9张图片4.总结与答案

面试题01 mysql使用innodb引擎,请简述mysql索引的最左前缀如何优化orderby语句_第10张图片

本人知识有限,有错误的请跟我反馈,非常感谢

你可能感兴趣的:(面试题,数据库,mysql,数据库)