举例
CREATE TABLE dept(
dept_id INT PRIMARY KEY AUTO_INCREMENT, 主键,自增
dept_name VARCHAR(20)
);CREATE TABLE emp(
emp_id INT PRIMARY KEY AUTO_INCREMENT, 主键,自增
emp_name VARCHAR(20) UNIQUE, 唯一索引
dept_id INT,
CONSTRAINT emp_dept_id_fk FOREIGN KEY(dept_id) REFERENCES dept(dept_id) 外键
);
显式创建表时创建索引的话,基本语法格式如下:
CREATE TABLE table_name [col_name data_type]
[UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [index_name] (col_name [length]) [ASC |
DESC]
创建普通索引举例
CREATE TABLE book(
book_id INT ,
book_name VARCHAR(100),
authors VARCHAR(100),
info VARCHAR(100) ,
comment VARCHAR(100),
year_publication YEAR,
INDEX(year_publication) 普通索引
);
创建唯一索引举例
CREATE TABLE test1(
id INT NOT NULL,
name varchar(30) NOT NULL,
UNIQUE INDEX uk_idx_id(id) 唯一unique
);
CREATE TABLE student (
id INT(10) UNSIGNED AUTO_INCREMENT ,
student_no VARCHAR(200),
student_name VARCHAR(200),
PRIMARY KEY(id) 主键
);
删除主键索引
ALTER TABLE student
drop PRIMARY KEY ;
修改主键索引:必须先删除掉(drop)原索引,再新建(add)索引
创建单列索引
CREATE TABLE test2(
id INT NOT NULL,
name CHAR(50) NULL,
INDEX single_idx_name(name(20))
);
创建组合索引
CREATE TABLE test3(
id INT(11) NOT NULL,
name CHAR(30) NOT NULL,
age INT(11) NOT NULL,
info VARCHAR(255),
INDEX multi_idx(id,name,age)
);
创建全文索引,FullTEXT全文索引可以用于全文搜索,并且只为char,varchar,text列创建,索引总是对整个列进行,不支持局部(前缀)索引
CREATE TABLE test4(
id INT NOT NULL,
name CHAR(30) NOT NULL,
age INT NOT NULL,
info VARCHAR(255),
FULLTEXT INDEX futxt_idx_info(info(可以加长度,表示只比较前xxx长度)) 全文索引
) ENGINE=MyISAM;
在MySQL5.7及之后版本中可以不指定最后的ENGINE了,因为在此版本中InnoDB支持全文索引。
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR (200),
body TEXT,
FULLTEXT index (title, body) 组合字段全文索引
) ENGINE = INNODB ;
CREATE TABLE `papers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(200) DEFAULT NULL,
`content` text,
PRIMARY KEY (`id`),
FULLTEXT KEY `title` (`title`,`content`) 组合字段全文索引
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
全文索引和like的语法规则
like
SELECT * FROM papers WHERE content LIKE ‘%查询字符串%’;FULLTEXT KEY
SELECT * FROM papers WHERE MATCH(title,content) AGAINST (‘查询字符串’);
注意点:
创建空间索引
空间索引创建中,要求空间类型的字段必须为 非空 。
CREATE TABLE test5(
geo GEOMETRY NOT NULL,
SPATIAL INDEX spa_idx_geo(geo)
) ENGINE=MyISAM;
在已经存在的表中创建索引可以使用ALTER TABLE语句或者CREATE INDEX语句。
ALTER TABLE table_name ADD [UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY]
[index_name] (col_name[length],...) [ASC | DESC]
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name
ON table_name (col_name[length],...) [ASC | DESC]
使用ALTER TABLE删除索引 ALTER TABLE删除索引的基本语法格式如下:
ALTER TABLE table_name DROP INDEX index_name;
使用DROP INDEX语句删除索引 DROP INDEX删除索引的基本语法格式如下:
DROP INDEX index_name ON table_name;
删除表中的列时,如果要删除的列为索引的组成部分,则该列也会从索引中删除。如果组成
索引的所有列都被删除,则整个索引将被删除。
举例:分别在MySQL 5.7版本和MySQL 8.0版本中创建数据表ts1
CREATE TABLE ts1(a int,b int,index idx_a_b(a,b desc));
从结果可以看出,索引仍然是默认的升序
在MySQL 8.0版本中查看数据表ts1的结构,结果如下:
从结果可以看出,索引已经是降序了。下面继续测试降序索引在执行计划中的表现。
分别在MySQL 5.7版本和MySQL 8.0版本的数据表ts1中插入800条随机数据,执行语句如下:
从结果可以看出,索引已经是降序了。下面继续测试降序索引在执行计划中的表现。分别在MySQL 5.7版本和MySQL 8.0版本的数据表ts1中插入800条随机数据,执行语句如下:
DELIMITER //
CREATE PROCEDURE ts_insert()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i < 800
DO
insert into ts1 select rand()*80000,rand()*80000;
SET i = i + 1;
END WHILE;
commit;
END //
DELIMITER ;CALL ts_insert()
mysql5.7执行查询计划
从结果可以看出,执行计划中扫描数为799,而且使用了Using filesort。
Using filesort是MySQL中一种速度比较慢的外部排序,能避免是最好的。多数情况下,管理员可以通过优化索引来尽量避免出现Using filesort,从而提高数据库执行速度。
mysql8.0执行查询计划
在MySQL 8.0版本中查看数据表ts1的执行计划。从结果可以看出,执行计划中扫描数为5,而且没有使用Using filesort。
即mysql8比5.7多了倒叙索引,虽然5.7的语法支持,但还是升序索引。
在MySQL 5.7版本及之前,只能通过显式的方式删除索引。此时,如果发现删除索引后出现错误,又只能通过显式创建索引的方式将删除的索引创建回来。如果数据表中的数据量非常大,或者数据表本身比较大,这种操作就会消耗系统过多的资源,操作成本非常高。
从MySQL 8.x开始支持 隐藏索引(invisible indexes) ,只需要将待删除的索引设置为隐藏索引,使查询优化器不再使用这个索引(即使使用force index(强制使用索引),优化器也不会使用该索引),确认将索引设置为隐藏索引后系统不受任何响应,就可以彻底删除索引。 这种通过先将索引设置为隐藏索引,再删除索引的方式就是软删除
数据准备:表结构
索引本身可以起到约束作用,比如唯一索引,主键索引都是可以有唯一约束,因此在数据表中,如果某个字段是唯一性的,就可以直接创建唯一性索引或主键索引,这样可以更快的通过该索引来确定某条记录
例如上表student_info的id,student_id
业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。(来源Alibaba)
说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的。
某个字段在SELECT语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率
索引就是让数据按照某种顺序进行存储或检索,因此当我们使用 GROUP BY 对数据进行分组查询,或者使用 ORDER BY 对数据进行排序的时候,就需要 对分组或者排序的字段进行索引 。如果待排序的列有多个,那么可以在这些列上建立 组合索引 。
对数据按照某个条件进行查询后再进行 UPDATE 或 DELETE 的操作,如果对 WHERE 字段创建了索引,就能大幅提升效率。原理是因为我们需要先根据 WHERE 条件列检索出来这条记录,然后再对它进行更新或删除。如果进行更新的时候,更新的字段是非索引字段,提升的效率会更明显,这是因为非索引字段更新不需要对索引进行维护。
因为索引会对数据按照某种顺序进行排序,所以在去重的时候也会快很多
创建索引注意事项:
首先, 连接表的数量尽量不要超过 3 张 ,因为每增加一张表就相当于增加了一次嵌套的循环,数量级增长会非常快,严重影响查询的效率。
其次, 对 WHERE 条件创建索引 ,因为 WHERE 才是对数据条件的过滤。如果在数据量非常大的情况下,没有 WHERE 条件过滤是非常可怕的。
最后, 对用于连接的字段创建索引 ,并且该字段在多张表中的 类型必须一致 。比如 course_id 在student_info 表和 course 表中都为 int(11) 类型,而不能一个为 int 另一个为 varchar 类型。虽然都能查到,但是是由于mysql做了隐式转换,使用了函数,一旦使用函数,索引失效
假设字符串很长,那么存储一个字符串就需要占用很大的存储空间,在我们为字符串建立索引时,对应的B+树就有两个问题:
如果字符串截取少了,重复内容太多,散列度低,截取多了,达不到节省存储空间的效果,那么问题来了,应该截取多少字符串长度作为索引呢?
扩展:在varchar字段建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际的文本区分度决定索引长度,索引的长度和区分度是一对矛盾体,一般对字符串类型的数据,长度达到20,区分度高达90%以上,可以使用
count/(distinct left(列名,索引长度))/count(*)
的区分度来确定,这个值越接近1,则对应的索引长度越合适
关于前缀索引的问题:
groupby,orderby时,会有不准的情况,这一点很好理解
这一点很好理解,散列度高了,进行索引查找时获取值更少
最左原则
建议单表不超过6个,
数据量小,不使用索引的情况下查询速度本来就很快,如果创建索引,不仅占用磁盘空间,而且查询的时候,还得有回表操作,以及对增删改操作的性能有影响,所以数据量小的表不建议使用索引
例如性别
100万行数据(男女一样的情况下)如果查找性别为男的数据,如果为性别创建了索引,则会需要去二级索引中获取到50万条数据,再回表对聚簇索引进行查找,而且还降低增删改的效率,实际的查询速度也没有多大提升,这样子的开销有可能比不创建索引的开销还大
当数据量重复度大,高于10%时,就不需要对这个字段添加索引
例如身份证、UUID(在索引比较时需要转为ASCII,并且插入时可能造成页分裂)、MD5、HASH、无序长字符串等。