当前位置: 首页 > news >正文

数据库索引

🎯 本文专栏:MySQL深入浅出
🚀 作者主页:小度爱学习

在这里插入图片描述

数据库索引

索引(index):和view等一样,索引也是一种数据库对象。

索引是一种特殊的数据库结构,可以用来快速查询数据库表中的特定记录。索引是提高数据库性能的重要方式。MySQL中,所有的数据类型都可以被索引。MySQL的索引包括普通索引、唯一性索引、全文索引、单列索引、多列索引和空间索引等。

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。(注意:一般数据库默认都会为主键生成索引)。

如果说,没有任何加快查询的方案(没有索引),我们查询数据只能做全表扫描匹配,效率非常低!!!

借助一些数据结构与算法在手段,实现数据的快速检索,这就是数据库索引。

如果没有索引进行匹配,则条件查询时,会进行全表扫描【全表匹配】,性能非常差。

什么是索引

模式(schema)中的一个数据库对象
在数据库中用来加速对表的查询
通过使用快速路径访问方法快速定位数据,减少了磁盘的I/O
与表独立存放,但不能独立存在,必须属于某个表
由数据库自动维护,表被删除时,该表上的索引自动被删除。
索引的作用类似于书的目录,几乎没有一本书没有目录,因此几乎没有一张表没有索引。

索引的原理

就是把无序的数据变成有序的查询

  1. 把创建的索引的列的内容进行排序
  2. 对排序结果生成倒排表
  3. 在倒排表内容上拼上数据地址链
  4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

索引优缺点

索引的优点:

  • 可以提高检索数据的速度,这是创建索引的最主要的原因
  • 对于有依赖关系的子表和父表之间的联合查询时,可以提高查询速度
  • 使用分组和排序子句进行数据查询时,同样可以显著节省查询中分组和排序的时间。

索引的缺点:

  • 创建和维护索引需要耗费时间,耗费时间的数量随着数据量的增加而增加
  • 索引需要占用物理空间,每一个索引要占一定的物理空间
  • 增加、删除和修改数据时,要动态的维护索引,造成数据的维护速度降低了。

索引分类

索引分为聚簇索引和非聚簇索引两种,聚簇索引是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。

MySQL的索引包括普通索引、惟一性索引、全文索引、单列索引、多列索引和空间索引等。

索引的设计原则

为了使索引的使用效率更高,在创建索引的时候必须考虑在哪些字段上创建索引和创建什么类型的索引。本小节将向读者介绍一些索引的设计原则。

  1. 选择惟一性索引
  2. 为经常需要排序、分组和联合操作的字段建立索引
  3. 为常作为查询条件的字段建立索引
  4. 限制索引的数目
  5. 尽量使用数据量少的索引
  6. 尽量使用前缀来索引
  7. 删除不再使用或者很少使用的索引

创建索引的3种方式

创建索引是指在某个表的一列或多列上建立一个索引,以便提高对表的访问速度。创建索引有三种方式,这三种方式分别是:

  • 创建表的时候创建索引
  • 在已经存在的表上创建索引
  • 使用ALTER TABLE语句来创建索引

1.创建表时创建索引

创建表的时候可以直接创建索引,这种方式最简单、方便。其基本形式如下:
CREATE TABLE 表名 ( 属性名 数据类型 [完整性约束条件],
属性名 数据类型 [完整性约束条件],
…
属性名 数据类型
[UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY
[别名](属性名1 [(长度)] [ASC | DESC])
);-- 例如:
create table emp(id int auto_increment,name varchar(50),age int default 18,nickname varchar(255),gender enum("男", "女"),-- 主键索引【主键约束就是主键索引】primary key(id),-- 唯一索引unique index (name),-- 注意:username创建了一个普通索引-- 也是单列索引index (nickname),-- 多列索引index(age, gender)
)

1、普通索引

# 直接创建索引
CREATE INDEX index_name ON table(column(length))# 创建表的时候同时创建索引
Create table index1(Id int,Name varchar(20),Sex boolean,index(id),
);# 修改表结构的方式添加索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length))# 查询索引
Show create table index1 \G# 查询某张表中索引情况
-- 注意:查看当前表中索引创建情况
show index from table_name;# 使用计划查询SQL使用索引情况
Explain select * from index1 where id=1 \G# 删除索引
DROP INDEX index_name ON table

2、创建唯一性索引 ,当然也有多种创建方式

Create table index2(Id int unique,Name varchar(20),Unique index index2_id(id asc)
);

3、创建全文索引(FULLTEXT)

# MySQL从3.23.23版开始支持全文索引和全文检索,FULLTEXT索引仅可用于 MyISAM 表;
# 他们可以从CHAR、VARCHAR或TEXT列中作为CREATE TABLE语句的一部分被创建,
# 或是随后使用ALTER TABLE 或CREATE INDEX被添加。
# 对于较大的数据集,将你的资料输入一个没有FULLTEXT索引的表中,
# 然后创建索引,其速度比把资料输入现有FULLTEXT索引的速度更为快。
# 不过切记对于大容量的数据表,生成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。只能创建在char,varchartext类型的字段上。
create table index3(Id int,Info varchar(20),Fulltext index index3_info(info)
);explain select * from table where id=1;
EXPLAIN分析结果的含义:table:这是表的名字。type:连接操作的类型,ALLindex、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)possible_keys:可能可以利用的索引的名字Key:它显示了MySQL实际使用的索引的名字。如果它为空(或NULL),则MySQL不使用索引。key_len:索引中被使用部分的长度,以字节计。ref:它显示的是列的名字(或单词“const”),MySQL将根据这些列来选择行rows:MySQL所认为的它在找到正确的结果之前必须扫描的记录数。显然,这里最理想的数字就是1Extra:这里可能出现许多不同的选项,其中大多数将对查询产生负面影响

4、创建单列索引

Create table index4(Id int,Subject varchar(30),Index index4_st(subject(10))
); 

5、创建多列索引
使用多列索引时一定要特别注意,只有使用了索引中的第一个字段时才会触发索引。
如果没有使用索引中的第一个字段,那么这个多列索引就不会起作用。
也就是说多个单列索引与单个多列索引的查询效果不同,因为执行查询时,
MySQL只能使用一个索引,会从多个索引中选择一个限制最为严格的索引。

Create table index5(Id int,Name varchar(20),Sex char(4),Index index5_ns(name,sex)
);

6、创建空间索引

Create table index6(Id int,Space geometry not null,Spatial index index6_sp(space)
)engine=myisam;建空间索引时,表的存储引擎必须是myisam类型,而且索引字段必须有非空约束。空间数据类型包括
geometry,point,linestringpolygon类型等。平时很少用到。

2.create index

首先保证已经存在表,才能使用这个命令创建索引。

在已经存在的表上,可以直接为表上的一个或几个字段创建索引。

基本形式如下:help create index
CREATE [ UNIQUE | FULLTEXT | SPATIAL ]  INDEX 索引名
ON 表名 (属性名 [ (长度) ] [  ASC | DESC] );-- 使用create index
create index age_index on stus2(age);
-- 使用alter(索引是作用表的)
ALTER TABLE table_name ADD INDEX index_name ON (column)1.创建普通索引CREATE INDEX index_name ON table(column(length))2.创建惟一性索引CREATE UNIQUE INDEX indexName ON table(column(length))3.创建全文索引CREATE FULLTEXT INDEX index_content ON article(content)4.创建单列索引CREATE INDEX index3_name on index3 (name(10));5.创建多列索引6.创建空间索引

3.ALTER TABLE

用ALTER TABLE语句来创建索引,也是存在表的情况下。

在已经存在的表上,可以通过ALTER TABLE语句直接为表上的一个或几个字段创建索引。基本形式如下:
ALTER  TABLE 表名  ADD  [ UNIQUE | FULLTEXT | SPATIAL ]  INDEX 
索引名(属性名 [ (长度) ] [ ASC | DESC];1.创建普通索引ALTER TABLE table_name ADD INDEX index_name (column(length))2.创建惟一性索引ALTER TABLE table_name ADD UNIQUE indexName (column(length))3.创建全文索引ALTER TABLE index3 add fulltext index index3_name(name);4.创建单列索引ALTER TABLE index3 add index index3_name(name(10));5.创建多列索引
6.创建空间索引

删除索引

删除索引是指将表中已经存在的索引删除掉。一些不再使用的索引会降低表的更新速度,影响数据库的性能。
对于这样的索引,应该将其删除。本节将详细讲解删除索引的方法。
对应已经存在的索引,可以通过DROP语句来删除索引。

基本形式如下:
DROP  INDEX 索引名  ON 表名 ;-- 查看索引名称
show index from emp;
-- 根据索引名称来删除索引,age是索引名称
drop index age on emp;案例:
1、 在数据库job下创建workInfo表。创建表的同时在id字段上创建名为index_id的唯一性索引,而且以
降序的格式排列。workInfo表内容如下所示字段描述 数据类型 主键 外键 非空 唯一 自增id 编号 INT(10) 是 否 是 是  是name 职位名称 VARCHAR(20) 否 否 是 否 否type 职位类别 VARCHAR(10) 否 否 否 否 否address 工作地址 VARCHAR(50) 否 否 否 否 否wage 工资 INT 否 否 否 否 否contents 工作内容 TINYTEXT 否 否 否 否 否extra 附加信息 TEXT 否 否 否 否 否CREATE TABLE workInfo(id INT(10) NOT NULL UNIQUE PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20) NOT NULL,type VARCHAR(10),address VARCHAR(50),tel VARCHAR(20),wage INT,content TINYTEXT,extra TEXT,UNIQUE INDEX index_id(id DESC));2 、使用create index语句为name字段创建长度为10的索引index_nameCREATE INDEX index_name ON workInfo(name(10));3 、使用alter table语句在type和address上创建名为index_t的索引ALTER TABLE workInfo ADD INDEX index_t(type,address);4 、将workInfo表的存储引擎更改为MyISAM类型ALTER TABLE workInfo ENGINE=MyISAM;5 、使用alter table语句在extra字段上创建名为index_ext的全文索引ALTER TABLE workInfo ADD FULLTEXT INDEX index_ext(extra);6 、删除workInfo表的唯一性索引index_idDROP INDEX index_id ON workInfo;
1、创建测试表
create table test1(id int,num int,pass varchar(50)
);create table test2(id int,num int,pass varchar(50),index idIdx (id)
);create table test3(id int,num int,pass varchar(50)
);2、向表test1里插入1000000条数据for ((i=1;i<=1000000;i++));do `mysql -p123456 -uroot -e "insert into it.test1values($i,floor($i+rand()*$i),md5($i));"`; done > /tmp/mysql.txt  2>&1# 注意:测试时可以插入300000条记录
mysql> select count(*) from test1;
+----------+
| count(*) |
+----------+
|  300000 |
+----------+
1 row in set (0.12 sec)3、在有索引和没有索引的情况下执行查询
1)没有创建索引时查询
mysql> reset query cache;
mysql> explain select num,pass  from test3 where id>=5000 and id<5050;2)创建索引后再次查询
mysql> reset query cache;
mysql> explain select num,pass  from test2 where id>=5000 and id<5050;4、在有索引和没有索引的情况下新增数据
1)没有创建索引时插入数据mysql> insert into test3 select * from test1;Query OK, 300000 rows affected (1.00 sec)
Records: 300000 Duplicates: 0  Warnings: 02)创建索引后再次插入数据mysql> insert into test2 select * from test1;Query OK, 300000 rows affected (1.17 sec)
Records: 300000 Duplicates: 0  Warnings: 0

MySQL使用索引的场景

1) 快速查找符合where条件的记录2) 快速确定候选集。若where条件使用了多个索引字段,则MySQL会优先使用能使候选记录集规模最小的那
个索引,以便尽快淘汰不符合条件的记录。3) 如果表中存在几个字段构成的联合索引,则查找记录时,这个联合索引的最左前缀匹配字段也会被自动作为索引来加速查找。
例如,若为某表创建了3个字段(c1, c2, c3)构成的联合索引,则(c1), (c1, c2), (c1, c2, c3)均会作为索引,(c2, c3)就不会被作为索引,而(c1, c3)其实只利用到c1索引。4) 多表做join操作时会使用索引(如果参与join的字段在这些表中均建立了索引的话)。5)若某字段已建立索引,求该字段的min()max()时,MySQL会使用索引6)对建立了索引的字段做sort或group操作时,MySQL会使用索引1) B-Tree可被用于sql中对列做比较的表达式,如=, >, >=, <, <=between操作2)like语句的条件是不以通配符开头的常量串,MySQL也会使用索引。
比如,SELECT * FROM tbl_name WHERE key_col LIKE 'Patrick%'SELECT * FROM
tbl_name WHERE key_col LIKE 'Pat%_ck%'可以利用索引,而SELECT * FROM tbl_name WHERE
key_col LIKE '%Patrick%'(以通配符开头)和SELECT * FROM tbl_name WHERE key_col LIKE
other_col(like条件不是常量串)无法利用索引。
对于形如LIKE '%string%'sql语句,若通配符后面的string长度大于3,则MySQL会利用Turbo
Boyer-Moore algorithm算法进行查找.3) 若已对名为col_name的列建了索引,则形如"col_name is null"SQL会用到索引。4) 对于联合索引,sql条件中的最左前缀匹配字段会用到索引。5)sql语句中的where条件不只1个条件,则MySQL会进行Index Merge优化来缩小候选集范围MySQL只对一下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。而理论上每张表里面最多可创建16个索引(版本不同,可能会有变化)。
MySQL索引的优化

上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。

因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。

索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句。下面是一些总结以及收藏的MySQL索引的注意事项和优化方法。

何时使用聚集索引或非聚集索引

image-20210416003527118

非聚簇索引和聚簇索引

非聚簇索引

索引节点的叶子页面就好比一片叶子。叶子头便是索引键值。

先创建一张表:

CREATE TABLE `user` ( 
`id` INT NOT NULL ,
`name` VARCHAR NOT NULL ,
`class` VARCHAR NOT NULL);

对于MYISAM引擎,如果创建 id 和 name 为索引。对于下面查询:

select * from user where id = 1

会利用索引,先在索引树中快速检索到 id,但是要想取到id对应行数据,必须找到改行数据在硬盘中的存储位置,因此MYISAM引擎的索引,叶子页面上不仅存储了主键id 还存储着 数据存储的地址信息。如图:

image-20210416004053399

像这样的索引就称为非聚簇索引。

非聚簇索引的二级索引与主键索引类似。假设我们对name添加索引,那么name的索引树叶子将是如下结构:

image-20210416004133181

聚簇索引

对于非聚簇索引来说,每次通过索引检索到所需行号后,还需要通过叶子上的磁盘地址去磁盘内取数据(回行)消耗时间。为了优化这部分回行取数据时间,InnoDB 引擎采用了聚簇索引。

聚簇索引,即将数据存入索引叶子页面上。对于 InnoDB 引擎来说,叶子页面不再存该行对应的地址,而是直接存储数据:

image-20210416004259312

这样便避免了回行操作所带来的时间消耗。 使得 InnoDB 在某些查询上比 MyISAM 还要快!

关于查询时间,一般认为 MyISAM 牺牲了功能换取了性能,查询更快。但事实并不一定如此。多数情况下,MyISAM 确实比 InnoDB 查的快 。但是查询时间受多方面因素影响。InnoDB 查询变慢得原因是因为支持事务、回滚等等,使得 InnoDB的叶子页面实际上还包含有事务id(换句话说就是版本号) 以及回滚指针。

在二级索引方面, InnoDB 与 MyISAM 有很大区别。

InnoDB默认对主键建立聚簇索引。如果你不指定主键,InnoDB会用一个具有唯一且非空值的索引来代替。如果不存在这样的索引,InnoDB会定义一个隐藏的主键,然后对其建立聚簇索引。一般来说,InnoDB 会以聚簇索引的形式来存储实际的数据,它是其它二级索引的基础。

假设对 InnoDB 引擎上表name字段加索引,那么name索引叶子页面则只会存储主键id:

image-20210416004427275

检索时,先通过name索引树找到主索引id,再通过id在主索引树的聚簇索引叶子页面取出数据。

相关文章:

  • 使用 docker 安装 nacos3.x
  • MKS RGA 校准调试MKS eVision和Vision 1000p RGA步骤(图文并茂)
  • 麦科信获评CIAS2025金翎奖【半导体制造与封测领域优质供应商】
  • DeepInjectSQL - 基于 AI 生成对抗网络(GAN)的下一代 SQL 注入自动化漏洞猎手
  • wordpress自学笔记 第二节: 3种独立站商城横幅的制作
  • 【深度学习新浪潮】苹果在显示算法技术上的研发进展调研
  • [论文阅读]Deeply-Supervised Nets
  • Qwen智能体qwen_agent与Assistant功能初探
  • clahe算法基本实现
  • websocketd 10秒教程
  • 图上思维:基于知识图的大型语言模型的深层可靠推理
  • Excel提取单元格特定符号左右两边内容
  • OPENSSL-1.1.1的使用及注意事项
  • (pnpm)引入 其他依赖失败,例如‘@element-plus/icons-vue‘失败
  • 矩阵短剧系统:如何用1个后台管理100+小程序?深度解析多端绑定技术
  • vue搭建+element引入
  • 2025数维杯数学建模A题完整论文模型代码:空中芭蕾
  • 霸王茶姬微信小程序自动化签到系统完整实现解析
  • 使用Kotlin Flow实现Android应用的响应式编程
  • 小刚说C语言刷题—1004阶乘问题
  • 时隔14个月北京怀柔区重启供地,北京建工以3.59亿元摘得
  • 壹基金发布2024年度报告,公益项目惠及937万人次
  • 国家主席习近平同普京总统共见记者
  • 夜读丨母亲的手擀面
  • 上海:5月8日起5年以上首套个人住房公积金贷款利率下调至2.6%
  • 韩国法院将李在明所涉案件重审日期延至大选后