SELECT `TABLE_NAME` AS `Table`, `NON_UNIQUE`, `INDEX_NAME` AS `Key_name`, `COLUMN_NAME` AS `Column_name`, `INDEX_TYPE` AS `Index_type`FROM information_schema.statisticsWHERE `TABLE_NAME` = 'users' AND `TABLE_SCHEMA` = DATABASE();
CREATE FULLTEXT INDEX idx_article_content ON articles(content);
示例表:CREATE TABLE `employees` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名', `age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄', `position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位', `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间', PRIMARY KEY (`id`), KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记录表';INSERT INTO employees(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW());INSERT INTO employees(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW());INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());
全值匹配
最左前缀
联合索引只会建立1棵B+树,index(note,b)在索引构建上,包含了两个意思:
1、先把各个记录按照note列进行排序。
2、在记录的note列相同的情况下,采用b列进行排序
索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
存储引擎不能使用索引中范围条件右边的列
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='manager';
只用到了 name和age
尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少 select * 语句
**.mysql在使用不等于(!=或者<>),****not in ,not exists **的时候无法使用索引会导致全表扫描
-- 插入一些示例数据drop procedure if exists insert_emp;delimiter ;;create procedure insert_emp()begin declare i int; set i = 1; while(i <= 100000) do insert into employees(name, age, position) values (CONCAT('zhuge', i), i, 'dev'); set i = i + 1; end while;end;;delimiter ;call insert_emp();
联合索引第一个字段用范围不会走索引
EXPLAIN SELECT * FROM employees WHERE name > 'LiLei' AND age = 22 AND position ='manager';
-- 关闭查询缓存set global query_cache_size=0; set global query_cache_type=0;-- 执行时间0.333sSELECT * FROM employees WHERE name > 'LiLei';-- 执行时间0.444sSELECT * FROM employees force index(idx_name_age_position) WHERE name > 'LiLei';
覆盖索引优化
EXPLAIN SELECT name,age,position FROM employees WHERE name > 'LiLei' AND age = 22 AND position ='manager';
in和or在表数据量比较大的情况会走索引,在表记录不多的情况下会选择全表扫描
EXPLAIN SELECT * FROM employees WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager';EXPLAIN SELECT * FROM employees WHERE name in ('LiLei','HanMeimei','Lucy') AND age in (11 , 22, 33) AND position ='manager';EXPLAIN SELECT * FROM employees WHERE (name = 'LiLei' or name = 'HanMeimei') AND age = 22 AND position ='manager';EXPLAIN SELECT * FROM employees WHERE (name = 'LiLei' or name = 'HanMeimei') AND (age = 11 or age = 22) AND position ='manager';
对于辅助的联合索引(name,age,position),正常情况按照最左前缀原则,SELECT * FROM employees WHERE name like 'LiLei%' AND age = 22 AND position ='manager' 这种情况只会走name字段索引,因为根据name字段过滤完,得到的索引行里的age和position是无序的,无法很好的利用索引。
MySQL 5.6引入了索引下推优化,可以在索引遍历过程中,对索引中包含的所有字段先做判断,过滤掉不符合条件的记录之后再回表,可以有效的减少回表次数。使用了索引下推优化后,上面那个查询在联合索引里匹配到名字是** 'LiLei' 开头的索引之后,同时还会在索引里过滤age和position**这两个字段,拿着过滤完剩下的索引对应的主键id再回表查整行数据。
一般这种范围查找的条件都要放在最后,之前讲过联合索引范围之后条件的是不能用索引的,但是对于当前这种情况依然用不到age这个索引字段,因为用户没有筛选sex字段,那怎么优化了?其实我们可以这么来优化下sql的写法:where province=xx and city=xx and sex in ('female','male') and age>=xx and age<=xx