MySQL(十一)索引的分类和创建原则
索引的创建与设计原则
1 索引的声明与使用
1.1 索引的分类
MySQL索引包括普通索引
、唯一性索引
、全文索引
、单列索引
、多列索引
和空间索引
- 按照逻辑结构划分,主要有四种:
普通索引
、唯一性索引
、主键索引
和全文索引
- 按照物理实现方式划分,主要有两种:
聚簇索引
和非聚簇索引
- 按照作用字段:
单列索引
和多列索引
(联合索引
)
多列索引即联合索引,当多个字段构成联合主键的时候则为聚簇索引,否则为非聚簇索引
普通索引
- 在创建普通索引的时候,不需要任何的限制条件,只是用于提高查询速度
- 这类索引可以创建在
任何数据类型
中,其值是否非空和唯一,取决于字段本身的完整性约束 - 创建索引之后,可以直接通过索引进行查询。
唯一性索引
- 使用
UNIQUE参数
可以设置索引为唯一索引 - 在创建唯一索引的时候,会限制索引的值必须是唯一的,但是允许有空值
- 在一张表中可以有多个唯一索引。
UNIQUE会自动创建唯一索引,并且可以通过删除字段的唯一索引来删除唯一性
主键索引
- 主键索引是一种特殊的唯一索引,也就是
NOT NULL + UNIQUE
,也即是聚簇索引 - 一张表中只能有一个主键索引
这是由主键索引的物理实现方式(聚簇索引)决定的:数据存储在文件中只能按照一种顺序(主键大小)进行存储
单列索引
- 即在单个字段上创建的索引
- 单列索引可以是普通索引,也可以是唯一性索引还可以是全文索引,只需要保证对应一个字段即可
- 一张表可以有多个单列索引
多列索引
- 即在多个字段组合上创建一个索引,该索引指向创建时对应的多个字段,可以通过这几个字段进行查询
- 但是在查询的时候,只有使用了第一个字段时索引才会被使用(和上面一样,这是由主键索引的物理实现方式决定的:数据存储在文件中只能按照一种顺序(一个列的大小)进行存储),即最
左前缀原则
全文索引
空间索引
1.2 创建索引
首先创建数据库和表
CREATE DATABASE dbtest2 CHARACTER SET 'utf8'
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的时候,会对
主键约束
、唯一性约束
和外键约束
的字段上,自动地添加相关的索引显示创建普通索引:语法如下
CREATE TABLE tableName [colName dataType ...]
[UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [indexName] (colName [length]) [ASC | DESC]
- UNIQUE | FULLTEXT | SPATIAL:可选参数,即唯一索引、全文索引和空间索引
- index和key作用相同,用来指定创建索引,一般情况下使用key
- indexName:索引名,不指定的话默认为列名
- colName:列名
- 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 idx_bname(book_name)
)
通过命令查看索引:
方式一:show create table tableName
mysql> show create table book\G
*************************** 1. row ***************************
Table: book
Create Table: CREATE TABLE `book` (
`book_id` int DEFAULT NULL,
`book_name` varchar(100) DEFAULT NULL,
`AUTHORS` varchar(100) DEFAULT NULL,
`info` varchar(100) DEFAULT NULL,
`COMMENT` varchar(100) DEFAULT NULL,
`year_publication` year DEFAULT NULL,
KEY `idx_bname` (`book_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3
1 row in set (0.01 sec)方式二:show index from tableName;
mysql> show index from book\G
*************************** 1. row ***************************
Table: book
Non_unique: 1 // 表示不是唯一
Key_name: idx_bname
Seq_in_index: 1
Column_name: book_name
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
1 row in set (0.09 sec)EXPLAIN性能分析工具
EXPLAIN SELECT * FROM book WHERE book_name = 'mysql'
可以看到查询语句possible_keys可能使用到的索引包括了idx_bname
创建表的时候添加唯一索引
CREATE TABLE book1 (
book_id INT,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info varchar(100),
COMMENT VARCHAR(100),
year_publication YEAR,
UNIQUE INDEX uk_idx_cmt(COMMENT)
); INSERT INTO book1 VALUES (1, 'mysql', NULL, NULL, 'mysql高级', NULL)
INSERT INTO book1 VALUES (2, 'mysql', NULL, NULL, 'mysql高级', NULL)
-- [Err] 1062 - Duplicate entry 'mysql高级' for key 'book1.uk_idx_cmt'
INSERT INTO book1 VALUES (2, 'mysql', NULL, NULL, NULL, NULL)
INSERT INTO book1 VALUES (2, 'mysql', NULL, NULL, NULL, NULL)
声明有唯一索引的字段,在添加数据的时候要保证数据的唯一性,但是可以多次添加NULL值,等效于添加唯一性约束
主键索引:通过主键约束的方式定义,即隐式的方式
INSERT INTO book1 VALUES (2, 'mysql', NULL, NULL, NULL, NULL) mysql> show index from book2\G
*************************** 1. row ***************************
Table: book2
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: book_id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
Visible: YES
Expression: NULL
1 row in set (0.04 sec)
同样删除索引也只能通过删除主键约束的方式:
ALTER TABLE book2
DROP PRIMARY KEY添加自增的主键不能删除
创建单列索引
前面的都是,这里就不再写了
创建联合索引
CREATE TABLE book3 (
book_id INT,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info varchar(100),
COMMENT VARCHAR(100),
year_publication YEAR,
INDEX multi_bid_bname_binf(book_id, book_name, info)
)
SHOW INDEX FROM book3;
Seq_in_index表示索引的排序顺序,该联合索引会按照id、name、info的顺序进行排序,并且查询的时候要求根据
最左前缀原则
先查询id才能使用索引EXPLAIN SELECT * FROM book3 WHERE book_id = 1 AND book_name = 'mysql'
-- possible keys : multi_bid_bname_binf EXPLAIN SELECT * FROM book3 WHERE book_name = 'mysql' = 1 AND book_id
-- possible keys : multi_bid_bname_binf EXPLAIN SELECT * FROM book3 WHERE book_name = 'mysql'
-- possible keys : NULL
最左前缀原则是由数据库表真实的物理存储结构决定的,底层使用的B+树按照联合主键的字段顺序大小进行排序,因此使用别的字段值无法进行检索
全文索引
全文检索使用match + against的方式查询:
select * from test4 where Match(name, info) against('检索字符串')
使用全文检索性能相较于like快很多,但是精度差(可能会少数据)
空间索引
② 创建表的时候添加索引
alter table
ALTER TABLE tableName ADD [UNIQUE | FULLTEXT | SPATIAL] INDEX indexName(colName ...)
create index on
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX indexName ON tableName(colName ...)
1.3 删除索引
使用场景
:当表中存在较多索引并且进行大量增删改操作的时候,可以先进行删除索引的操作,以减少增删改过程对于索引的维护。
- ALTER TABLE DROP INDEX对应ALTER TABLE ADD INDEX
ALTER TABLE book3
DROP INDEX multi_bid_bname_binf
- DROP INDEX ON 对应 CREATE INDEX ON
DROP INDEX multi_bid_bname_binf ON book3
对于使用
AUTO_INCREMENT
约束的字段不能删除其主键或者索引,前面页提到过,因为AUTO_INCREMENT
约束要求字段为主键或者UNIQUE
当删除、修改字段的时候,会自动对索引进行维护:
SHOW INDEX FROM book3;
book3 1 multi_bid_bname_binf 1 book_id A 0 YES BTREE YES
book3 1 multi_bid_bname_binf 2 book_name A 0 YES BTREE YES
book3 1 multi_bid_bname_binf 3 info A 0 YES BTREE YES
ALTER TABLE book3
DROP COLUMN book_name;
SHOW INDEX FROM book3;
book3 1 multi_bid_bname_binf 1 book_id A 0 YES BTREE YES
book3 1 multi_bid_bname_binf 2 info A 0 YES BTREE YES
2 MySQL 8.0 索引新特性
2.1 支持降序索引
降序索引会以降序存储键值,虽然在语法上mysql4.0就支持索引降序了,但是实际上DESC是被忽略的(使用反向扫描来实现降序),直到mysql 8.0 才开始真正支持降序索引(仅限于innoDB存储引擎)
使用降序索引意义重大,如一个查询,需要对多个列进行排序,而且顺序要求不一致,那么降序索引就能够避免数据库使用额外的文件排序
来实现反向扫描,从而提高性能。
举个栗子,首先在5.0 和 8.0 都创建一张表:
CREATE TABLE ts1 (
a int,
b int,
INDEX idx_a_b(a, b DESC)
)
然后编写一个存储过程添加一些数据:
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;
此时按照a升序、b升序检索,查看执行计划:
EXPLAIN SELECT * FROM ts1 ORDER BY a, b
1 SIMPLE ts1 index idx_a_b 10 799 100 Using index; Using filesort
可以看到使用了索引和文件排序
此时按照a升序、b降序检索,查看执行计划:
EXPLAIN SELECT * FROM ts1 ORDER BY a, b DESC
1 SIMPLE ts1 index idx_a_b 10 799 100 Using index
可以看到只使用了索引
而5.0版本的mysql则是也会使用文件排序,因为实际存储时仍按照b升序排列的
这里就不演示了
2.2 支持隐藏索引
使用场景
:在MySQL5.7及之前,只能通过显示的方式删除索引,此时如果发现索引删除后出现错误,则又需要再添加创建索引,如果此时表中已经存储了大量的数据或者表本身比较大,则就会消耗过多的资源,操作成本非常高。或者想要验证索引删除后的性能影响。
功能
:Mysql 8.0后支持的隐藏索引,只需要将待删除的索引设置为隐藏索引
,查询优化器
就不会使用这个索引(哪怕使用force index
也不会),确认删除索引不会出错后,再真正删除索引。这种通过设置隐藏索引,再删除索引的方式就是软删除。
主键不能设置为隐藏索引,当表中没有显示的主键,表中的第一个非空索引就会成为隐式主键,也不能设置隐藏索引
创建表的时候直接创建隐藏索引
CREATE TABLE book4 (
book_id INT,
book_name VARCHAR(100),
AUTHORS VARCHAR(100),
info varchar(100),
COMMENT VARCHAR(100),
year_publication YEAR,
INDEX multi_bid_bname_binf(book_id, book_name, info) INVISIBLE
) SHOW INDEX FROM book4
这时候尝试使用索引进行查询:
EXPLAIN SELECT * FROM book4 WHERE book_id = 1
创建表以后隐藏索引
ALTER TABLE book4
ADD UNIQUE INDEX uq_idx_bid(book_id) ALTER TABLE book4
ADD UNIQUE INDEX uq_idx_bname(book_name) INVISIBLE
修改索引可见性
ALTER TABLE book4
ALTER INDEX uq_idx_bname VISIBLE;
注意
索引被隐藏只是查询优化器不可见,但是仍然和正常索引一样是实时更新的,因此索引长时间被隐藏应该删除,避免影像增删改的性能
MySQL(十一)索引的分类和创建原则的更多相关文章
- MySQL 的索引和最左前缀原则
这两天看<构建高性能Web站点>这本书,感觉写的真是不错,很多实际项目中会碰到的问题都有所提及,今天看到一个最左前缀原则,以前也听说过,不过一直没搞明白,今天查了下. 通过实例理解单列索引 ...
- 【Mysql】—— 索引的分类
注意:索引是在存储引擎中实现的,也就是说不同的存储引擎,会使用不同的索引.MyISAM和InnoDB存储引擎:只支持BTREE索引,也就是说默认使用BTREE,不能够更换.MEMORY/HEAP存储引 ...
- Mysql联合索引的最左前缀原则以及b+tree
软件版本mysql5.7 根据官网的文档 https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html 查询条件要符合最左原 ...
- mysql 复合索引 为什么遵循最左原则
1,>mysql :多列索引 https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html 1>,B+树: h ...
- MySQL学习----索引的使用
一.什么是索引?为什么要建立索引? 索引用于快速找出在某个列中有一特定值的行,不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多,如果表中查询的 ...
- 【Mysql】索引简介
本文口味:番茄炒蛋,预计阅读:10分钟. 博客又停更了两个月,在这期间,对人生和世界多了许多思考.在人生的不同阶段,会对生活和世界有着不一样的认知,而认知的改变也会直接反应在行为模式之中. 对于生活的 ...
- 来了解一下Mysql索引的相关知识:基础概念、性能影响、索引类型、创建原则、注意事项
索引的基础概念索引类似于书籍的目录,要想找到一本书的某个特定主题,需要先查找书的目录,定位对应的页码:存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的值,然后根据匹配的索引找到对应的数据行 ...
- SQL优化 MySQL版 - 索引分类、创建方式、删除索引、查看索引、SQL性能问题
SQL优化 MySQL版 - 索引分类.创建方式.删除索引.查看索引.SQL性能问题 作者 Stanley 罗昊 [转载请注明出处和署名,谢谢!] 索引分类 单值索引 单的意思就是单列的值,比如说有 ...
- mysql 索引及索引创建原则
是什么 索引用于快速的查询某些特殊列的某些行.如果没有索引, MySQL 必须从第一行开始,然后通过搜索整个表来查询有关的行.表越大,查询的成本越大.如果表有了索引的话,那么 MySQL 可以很快的确 ...
- Mysql的索引调优详解:如何去创建索引以及避免索引失效
在正式介绍Mysql调优之前,先补充mysql的两种引擎 mysql逻辑分层 InnoDB:事务优先(适合高并发操作,行锁) MyISAM:性能优先(表锁) 查看使用的引擎: show variabl ...
随机推荐
- javascript数据类型,定义方法,(工厂模式及闭包的应用)
js数据类型分为两大类:一 值类型 二 引用类型 一 值类型 string number boolean null ...
- K8SYaml文件详解
一.K8S支持的文件格式 kubernetes支持YAML和JSON文件格式管理资源对象. JSON格式:主要用于api接口之间消息的传递 YAML格式:用于配置和管理,YAML是一种简洁的非标记性语 ...
- 第一章 对程序员来说CPU是什么
章节标题下方有几个问题,看完后便对第一章的内容有了大概的了解. 第一章观后感想: 第一章解释了CPU是什么,CPU相当于计算机的大脑,它的内部由数百万至数亿个晶体管构成. CPU所负责的就是解释和运行 ...
- HashMap中的Entry接口
利用Entry接口,快速又方便 import java.util.HashMap; import java.util.Map; public class MapDemo { public static ...
- 利用shell脚本提高访问GitHub速度
Github由于做了域名限制,所以访问比较慢,编写了个脚本达到做本地域名解析提高GitHub的访问速度 #!/usr/bin/env bash # 该脚本用来提升github的访问速度 ROOT_UI ...
- 代码版本管理git
git工作流程如下: 克隆 Git 资源作为工作目录. 在克隆的资源上添加或修改文件. 如果其他人修改了,你可以更新资源. 在提交前查看修改. 提交修改. 在修改完成后,如果发现错误,可以撤回提交并再 ...
- 利用fread读取二进制文件的bug
最近在做一个项目时需要读取二进制文件,我用C语言的fread进行读取,代码如下: FILE *fp; int read_data; fopen_s(&fp, file_path, " ...
- Python之简单文件操作
文件操作,open() 1 # open(file_path, mode='r', encoding='utf-8') 2 # file_path 目标文件路径 3 # mode 文件模式,参数r-读 ...
- git push 报错error: remote unpack failed: error Short read of block
1.解决办法:找管理代码的人给你开权限. 2如果你的push的命令写错的话,也是会出现远端拒绝的提示,所以记得检查自己的push 命令是否正确 另一种明显的权限拒绝的例子: 英语学习:to push ...
- restfull风格传参