索引分单列索引和组合索引
虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATe和DELETE,建立索引会占用磁盘空间
1.索引分类:
(1).主键索引:
primary key :主键索引,加速查找+约束(不为空且唯一)
primary key(id,name):组合主键索引
(2).唯一索引:
unique:唯一索引,加速查找+约束 (唯一)
unique(id,name):组合唯一索引
(3).普通索引:
index : 普通索引,加速查找
index(id,name):组合普通索引
(4).全文索引fulltext :搜索很长一篇文章的时候(很少使用),开发中一般使用Solr或ElasticSearch
(5).空间索引spatial :了解就好,几乎不用
#方法一:创建表时
创建索引
CREATE TABLE 表名 (
字段名1 数据类型 [约束条件…],
字段名2 数据类型 [约束条件…],
[UNIQUE | FULLTEXT | SPATIAL ] INDEX
[索引名] (字段名[(长度)] [ASC |DESC])
);
#方法二:CREATE创建索引
CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名
ON 表名 (字段名[(长度)] [ASC |DESC]) ;
#方法三:ALTER TABLE创建索引
ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX
索引名 (字段名[(长度)] [ASC |DESC]) ;
#查询索引
SHOW INDEX FROM 表名字;
#删除索引:
DROp INDEX 索引名 ON 表名字;
2.索引的创建与使用
#创建索引的前提:
(1).查询频繁的字段应创建索引
(2).唯一性差的字段不适合建索引,如gender='男'|'女'
(3).更新频繁的字段不适合建索引(维护索引B+树耗时)
(4).不会出现在WHERe子句中的字段不用建索引
#不使用索引的情况
(1)如果条件中有OR,所有使用到的字段都有索引才会使用索引
(2)组合索引,只有查询条件使用了最左边的列,索引一般就会被使用,否则不会使用索引
(3)LIKE '%xxx' 不会使用索引
(4)如果列类型是字符串,那么一定要在条件中将数据使用引号引用起来,否则不使用索引
#查看索引使用情况
SHOW STATUS LIKE 'Handler_read%';
#Handler_read_key:这个值越高越好,表示使用索引查询到的次数
#Handler_read_rnd_next:越高越不好,越高说明越低效
3.索引测试:
delimiter $$ #声明存储过程的结束符号为$$
create procedure auto_insert1()
BEGIN
declare i int default 1;
while(i<500000)do
insert into s1 values(i,concat('egon',i),'male',concat('egon',i,'@oldboy'));
set i=i+1;
end while;
END$$
delimiter ; #重新声明分号为结束符号
#调用存储过程生成测试数据
call auto_insert1();
#不借助索引查询
SELECT * FROM s1 WHERe id=233;
#创建索引后查询
CREATE INDEX idIndex ON s1(id);
SELECt * FROM s1 WHERe id=233;
#FULLTEXT索引 5.6版本中,InnoDB加入了对全文索引的支持 5.7.6版本MySQL内置了ngram全文解析器,用来支持亚洲语种的分词
#设置全文索引分词长度
SHOW VARIABLES LIKE 'ft_min_word_len';
#修改全文索引分词长度 [mysqld] 后面加入一行"ft_min_word_len=1",然后重启Mysql
#测试
use test;
CREATE TABLE test.students (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
user_name VARCHAR (200),
FULLTEXT (user_name) WITH PARSER ngram
) ENGINE = INNODB DEFAULT CHARSET=utf8mb4 COMMENT='students';
INSERT INTO `test`.`students` (`user_name`) VALUES ( '李思一');
INSERT INTO `test`.`students` (`user_name`) VALUES ( '李思二');
INSERT INTO `test`.`students` (`user_name`) VALUES ( '李思三');
INSERT INTO `test`.`students` (`user_name`) VALUES ( '李思适当放松的放松');
INSERT INTO `test`.`students` (`user_name`) VALUES ( '王武');
SELECt * from students where MATCH(user_name) AGAINST('李思');
SELECt * from students where MATCH(user_name) AGAINST('李思' IN NATURAL LANGUAGE MODE);
explain SELECt * from students where MATCH(user_name) AGAINST('李思');
4.知识点
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
InnoDB的索引和数据都存放于.ibd文件中,而MyISAM的索引和数据是分开的,索引在.MYI文件中
b+树:非叶子节点是索引时的指路人,叶子节点存储数据
b+树叶子节点存储了什么有样的数据?不同索引存储的内容是否一样?如果一样那坑定数据冗余?
b+树性质
索引字段要尽量的小:非叶子节点存储的指路人更多,可以使b+数高度更低,查询IO数更少
索引的最左匹配特性:
如何计算high=3的 B+ 树,可以存储的记录条数?
假设主键 ID 为 bigint 类型,长度为 8 字节,而指针大小在 InnoDB 源码中设置为 6 字节,这样一共 14 字节
show table status like 'tablename'G #avg_row_length = 153
show variables like'innodb_page_size'; #16384
innoDB 存储引擎,一个页的大小是 16K
非叶子节点能存放多少指针,16384/14=1170。
单个叶子节点(页)中的记录数=16K/153=105。
如果树的高度为 3,可以存放的记录行数= 1170*1170*105=143,734,500。