MySQL笔记8

一、索引

1.索引介绍

日常生活类比:如电话号码簿按"姓"查号码、字典按"字母"查单词,"姓"和"字母"可看作索引,按其查询就是按索引查询。

数据库定义:索引(index)是帮助MySQL高效获取数据的有序数据结构。数据库系统在数据之外维护满足特定查找算法的数据结构,这些结构引用数据,可实现高级查询算法。MySQL中所有数据类型都可被索引。

本质与作用:是一种特殊文件,用于快速查询数据库表中特定记录,是提高数据库性能的重要方式。

索引的特性:

是数据库模式(schema)中的数据对象。

有序数据结构,加速表的查询。

与表独立存放,但必须属于某个表,不能独立存在。

由数据库自动维护,表被删除时,表上的索引自动删除。

作用类似书的目录,几乎每张表都有索引。

2.表有无索引的查询方式

(1)无索引的查询方式

无索引时,执行SQL语句会全表扫描,即按照表格顺序遍历每一条数据获取查询数据,性能极低。

如下:建表时没有给任何列添加索引,插入测试数据并执行查询 age>30 的记录时。MySQL会执行全表扫描:数据库会从表的第1行开始,逐行检查 age 的值是否小于30。依次遍历 id=1 到 id=10 的所有记录,最终筛选出 age 符合条件的行。

这种方式需要遍历表中所有记录,当表中数据量很大时,查询性能会非常低

(2)有索引的查询方式

B+tree索引数据结构

组成:根节点→子节点→叶子结点

以3阶B+Tree为例,根节点下可有3个子节点,每个节点最多存储2个key、3个指针。

非叶子节点起索引作用,叶子节点存放数据,且叶子节点形成单向链表,每个节点通过指针指向下一个节点。MySQL对经典B+Tree优化,增加相邻叶子节点的链表指针,形成带顺序指针的B+Tree,提高区间访问性能,利于数据排序操作。

节点裂变:当节点中key值不满足阶数要求时开始裂变,中间元素向上分裂,所有key值转化到叶子节点。查询时,值小于key在左节点,大于等于key在右节点。

查询效率:通过B+Tree的索引结构,无需全表扫描,可快速定位到满足条件的数据,大幅提升查询性能。例如查询 age<30 的记录时,可通过B+Tree直接定位到对应叶子节点的数据,避免遍历所有记录。

Hash索引

原理:将无序数据转化为有序查询,步骤如下:

对索引列的每行数据计算Hash值。

对索引列的所有值再次通过Hash函数计算对应的槽位。

在槽位中记录key值和该行的Hash值,以此建立索引。

Hash冲突:当多个key值计算到同一个槽位时,通过Hash链表解决,在对应值后添加链表。

例:

第一步:先通过hash算出该表中每一行数据的hash值

第二步:拿到name字段的所有值,根据所获取的所有值再次通过内部的hash函数来计算每一个name值应该对应在hash表的哪一个槽位中;

第三步:如金庸这个键值计算出所对应的槽位是005,则在该槽位中记录key值和该行的hash值。以此类推

Hash冲突:

当两个或者多个key值计算的是同一个槽位则出现了hash冲突(hash碰撞),解决方式通过hash链表来解决,在对应的值后添加链表

特点:

仅支持等值比较( = 、 in ),不支持范围查询。

无法利用索引实现排序。

查询效率高,无冲突时通常只需一次查询。

R-tree空间索引

支持版本:MySQL 5.7及之后版本,且支持OpenGIS几何数据模型,使用较少,了解即可。

|------------|------|-----------------------------------------------------------------------------|
| 类型 | 含义 | 说明 |
| Geometry | 空间数据 | 任何一种空间类型 INSERT INTO 表名 (字段名) VALUES(POINT(121.4737, 31.2304)) |
| Point | 点 | 坐标值 INSERT INTO 表名 (字段名) VALUES (POINT(1, 2)) |
| LineString | 线 | 有一系列点连接而成,至少两个坐标点 INSERT INTO 表名 (字段名) VALUES (LINESTRING(1 2, 3 4, 5 6)) |
| Polygon | 多边形 | 由多条线组成 INSERT INTO 表名 (字段名) VALUES (POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))) |

操作:

两个语句在功能上是等价的,只是语法表述略有不同,都是为表中的 geom_point 字段创建一个空间索引。

3.索引优缺点

|---------------------------------------|----------------------------------------------------------|
| 优势 | 劣势 |
| 提高查询效率-提高数据检索的效率,降低数据库的IO成本 | 索引列也是要占用空间的 |
| 提高排序效率-通过索引列对数据进行排序,降低数据排序成本,降低CPU的消耗 | 索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行insert update、delete时,效率降低 |

4.索引分类

按 数据结构 分: B+tree索引、hash索引、full-text索引、r-tree 空间索引

按 物理存储 分:聚簇索引、二级索引(辅助索引)非聚簇索引

按 字段特性 分:主键索引、唯一索引、普通索引、前缀索引,fulltext index,spatial index

按 字段个数 分:单列索引、联合索引(多列)

|---------------|----------------------------------------|
| 索引结构 | 描述 |
| B+tree | 最常见的索引类型,大部分索引都支持B+tree |
| Hash索引 | 底层的数据结构是哈希表实现,只能精确匹配索引列的查询才有效,不支持范围查询 |
| R-tree空间索引 | 是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少 |
| Full-text全文索引 | 是一种通过建立倒排索引快速匹配文档的方式 |

|-----------|----------|--------|--------|
| 索引 | INNODB | MyISAM | Memory |
| B+tree | 支持 | 支持 | 支持 |
| Hash | 不支持 | 不支持 | 支持 |
| R-tree | 5.7版本后支持 | 支持 | 不支持 |
| Full-text | 5.6版本后支持 | 支持 | 不支持 |

5.索引语法

(1)创建

建表时创建索引:

CREATE TABLE 表名 ( 属性名 数据类型 [完整性约束条件], ... [UNIQUE | FULLTEXT | SPATIAL] INDEX | KEY [别名] (属性名1[(长度)] [ASC | DESC]));

(普通索引)

(唯一索引)

直接创建索引:

CREATE [ UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名 ON 表名 (字段名 [ (长度) ] [ ASC | DESC] );

通过 alter table 创建索引

ALTER TABLE 表名 ADD [ UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名(字段名 [ (长度) ] [ ASC | DESC]);

(主键索引是特殊的唯一索引)

(2)查看

查看表的创建语句(含索引):show create table table_name\G

查看表结构(含索引简要信息):desc table_name;

查看表的详细索引情况:show index from table_name;

查看SQL执行计划(索引使用情况):desc|Explain select * from table_name where id=1 \G

解释表中数据:

id:代表执行select子句或操作表的顺序;相同时,执行顺序由上至下;不同时,id的序号会递增,id值越大,优先级越高,越先被执行

select_type:查询的类型,主要用于区别普通查询,联合查询,子查询等复杂查询

simple:简单的 select 查询,查询中不包含子查询或 union 查询

primary:查询中若包含任何复杂的子部分,最外层查询则被标记为primary

subquery:在select 或where 列表中包含了子查询

derived (衍生):在from列表中包含的子查询结果标记为一张虚拟表, mysql会递归这些子查询,把结果放在临时表里也就是derived

union:第二个select出现在union之后,则被标记为union,若union包含在from子句的子查询中,外层select将被标记为derived

union result:从union表获取结果的select

table:显示数据是关于哪张表的

partitions:表分区的基本概念。表分区是将大表按规则拆分为多个物理存储单元的技术

type:查询类型从最好到最差依次是→null>system>const>eq_ref>ref>range>index>All,一般情况下,得至少保证达到range级别,最好能达到ref

null:是不指定表查询显示为null

system :表中只有一条数据,且存储引擎可以准确的统计到这条数据。system一般出现在MyISAM、memory类型的表查询中,很少用到

const:根据主键或者唯一索引显示const

ref:当连接条件使用了非唯一索引时,或者索引列与常量进行比较时显示

eq_ref:在进行多表连接查询时,表通过主键或唯一索引键进行等值查询

all:全表扫描

index:表示用了索引但是还是会遍历整个索引树

range:当where语句后面出现>或者<或者不等于等的时候会出现

possible_keys:显示可能应用在这张表中的索引,一个或多个,查询到的索引不一定是真正被用到的

key:实际使用的索引,如果为null,则没有使用索引,因此会出现possible_keys列有可能被用到的索引,但是key列为null,表示实际没用索引

key_len:不同类型占用的字节数不同(如 INT 占 4 字节,VARCHAR(10) 可能占 20+ 字节)

表示索引中使用的字节数,而通过该列计算查询中使用的 索引长度,在不损失精确性的情况下,长度越短越好,key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即,key_len是根据表定义计算而得不是通过表内检索出的

ref:列表示索引查找时所使用的参考值来源

|--------------------|----------------------|-----------------------------|
| ref值 | 说明 | 示例场景 |
| const | 主键 /唯一键等值匹配常量 | WHERE id = 123 |
| table.column | 跨表列引用 | JOIN ON a.id = b.user_id |
| func() | 函数或表达式结果 | WHERE YEAR(birthday) = 1990 |
| NULL | 无外部参考值(索引扫描) | WHERE age > 18 |
| const,table.column | 复合索引部分列使用常量,部分列使用列引用 | WHERE a=1 AND b=table.c |

理解 ref 值有助于分析查询如何利用索引,优化时应尽量让 ref 使用 const 或表列引用,避免 func() 或复杂表达式,以提升索引效率

rows:根据表统计信息及索引选用情况,大只估算出找到所需的记录所需要读取的行数

filtered:结合 Extra=Using where 时,filtered=100% 表示全表扫描且无有效过滤,filtered=10% 表示仅 10% 行满足条件

Extra:如果是 Using index/where 不需要回表查询,如果是using index condiltion 表示需要回表查询

|---------------|--------------------------|
| Table_catalog | 表目录,逻辑分组的标识默认就是def |
| table_schema | 表所属模式(所属数据库) |
| Table_name | 表名 |
| Non_unique | 0表示有,1表示没有 |
| Index_schema | 索引的数据库 |
| Index_name | 索引的名称 |
| Seq_in_index | 索引列数,如果是联合索引显示几列 |
| Collation | 排序方式A表示升序 |
| cardinality | 基数,唯一值的估算数量(估计数可能和实际偏差大) |
| Sub_part | 是否只索引一部分字符 |
| packed | 索引列值存储格式是否压缩处理 |
| null | 字段是否为空 |
| Is_visible | 是否可见,优化是可见考虑该索引,不可见不考虑 |
| experssion | 索引基于表达式(支持函数索引类型的库中) |

注:

如果Key是空的, 那么该列值的可以重复, 表示该列没有索引, 或者是一个非唯一的复合索引的非前导列

如果Key是PRI, 那么该列是主键的组成部分

如果Key是UNI, 那么该列是一个唯一值索引的第一列(前导列),并别不能含有空值(NULL)

如果Key是MUL, 那么该列的值可以重复, 该列是一个非唯一索引的前导列(第一列)或者是一个唯一性索引的组成部分但是可以含有空值NULL

(3)删除

指将表中已经存在的索引删除掉。一些不再使用的索引会降低表的更新速度,影响数据库的性能

删除普通索引:DROP INDEX 索引名 ON 表名; alter table 表名 drop index 索引名;

删除主键索引:alter table 表名 drop primary key;

6.全文索引

(1)基本概念

关键字为 fulltext ,用于查找文本中的关键字,基于相似度查询,类似搜索引擎的检索逻辑,而非简单的等值/模糊匹配。

like + % 适合少量文本的模糊匹配,但若处理大量文本数据,性能会极慢;全文索引在大数据量下检索速度远超 like + % ,但可能存在精度问题

在数据量较大时,将数据放入一个没有全局索引的表中,然后再用 create index 创建 fulltext 索引,要比先为一张表建立 fulltext 后再将数据写入的速度快很多;

MySQL 中的全文索引,有两个变量,最小搜索长度和最大搜索长度,对于长度小于最小搜索长度和大于最大搜索长度的词语,都不会被索引。通俗点就是说,想对一个词语使用全文索引搜索,那么这个词语的长度必须在以上两个变量的区间内。这两个的默认值可以使用以下命令查看:show variables like '%ft%';

参数解释:

|--------------------------|-----|-----|------|------------------------------|
| 参数名称 | 默认值 | 最小值 | 最大值 | 作用 |
| ft_min_word_len | 4 | 1 | 3600 | MyISAM引擎表创建全文索引最小词和最大词长度 |
| ft_query_expansion_limit | 20 | 0 | 1000 | MyISAM引擎表使用 查询扩展进行全文搜索的最大匹配数 |
| innodb_ft_min_token_size | 3 | 0 | 16 | InnoDB 引擎表全文索引包含的最小词长度 |
| innodb_ft_max_token_size | 84 | 10 | 84 | InnoDB 引擎表全文索引包含的最大词长度 |

(2)支持情况

版本:

MySQL 5.6 以前:仅 MyISAM 存储引擎支持;

MySQL 5.6 及以后:MyISAM 和 InnoDB 存储引擎均支持。

数据类型:仅 char 、 varchar 、 text 及其系列类型可创建全文索引。

(3)创建方式

建表时添加:

修改表结构时添加:

直接添加:

(4)使用语法

match (col1,col2,...) against(expr [search_modifier])

可以看到,第一条语句没有结果显示,第二条才有结果,这是因为:

单词 yo 长度为 2,小于上述参数的默认值(MyISAM 下小于 4,InnoDB 下小于 3),因此不会被全文索引收录,所以查询 match(content) against('yo') 没有结果。

单词 you 长度为 3,满足 InnoDB 引擎 innodb_ft_min_token_size (默认 3)的要求,会被全文索引收录,因此查询 match(content) against('you') 有结果

7.聚簇索引和非聚簇索引

(1)聚组索引

定义:索引 B+Tree 的叶子节点存储整行数据的主键索引,也称为聚簇索引。它是对磁盘实际数据重新组织以按指定列值排序的算法,数据存储顺序与索引顺序一致。

特点:

一张表仅允许存在一个聚簇索引,因为数据存储顺序只能有一种。

主键默认创建聚簇索引,修改聚簇索引实质是修改主键(主键需满足 not null 、 unique )。

InnoDB 自动生成规则:

有主键时,根据主键创建聚簇索引;

无主键时,用唯一且不为空的索引列作为聚簇索引;

若以上都不满足,InnoDB 会创建虚拟聚集索引。

查找过程:以 world 表(主键 id )为例,执行 select * from world where id = 4; 时,直接通过聚簇索引的 B+Tree 叶子节点找到整行数据(运维少年,18)。

(2)非聚族索引(辅助索引,二级索引 )

定义:索引 B+Tree 的叶子节点仅存储键值和索引列的非主键索引,也称为非聚簇索引

特点:

一个表可存在多个非聚簇索引。

索引存储与数据存储分离,找到索引后需根据主键回表查询才能获取完整数据

查找过程:以 world 表的 name 辅助索引为例,执行 select name from world where name='张三'; 时,先通过非聚簇索引的 B+Tree 找到 张三 对应的主键 id=1 ,再通过聚簇索引回表查询,最终获取数据。

8.乱建索引的后果

按照业务语句的需求创建合适的索引,并不是将所有列都建立索引:

每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大

修改表时,对索引的重构和更新很麻烦,越多的索引,会使表更新变得很浪费时间

优化器的负担会很重,有可能会影响到优化器的选择

9.索引失效

(1)索引列参与运算或函数操作

当查询条件中对索引列进行了运算(如算术运算)或函数操作时,索引会失效。例如 SELECT * FROM table WHERE YEAR(create_time) = 2025; 中,对 create_time 列使用 YEAR 函数后,该列的索引将无法被使用。

(2)字符串类型字段未加单引号

若字段是字符串类型(如 varchar ),查询时未给值加单引号,会导致索引失效。例如 SELECT * FROM t1 WHERE tel=12345678902; (若 tel 是 varchar 类型),因无单引号,索引无法生效;正确写法应为 tel='12345678902'。

(3)模糊查询的首部匹配

模糊查询中,仅尾部模糊匹配(如 like 'passwd%' )时索引不会失效;若首部模糊匹配(如 like '%passwd' ),索引会失效。

(4)OR连接条件的索引失效

当 OR 连接的多个条件中,部分列有索引、部分列无索引时,涉及的所有索引都会失效。例如 SELECT * FROM table WHERE idx_col=1 OR no_idx_col=2; ,即使 idx_col 有索引,该查询也会全表扫描。

(5)MySQL数据量评估导致的索引失效

当 MySQL 评估全表扫描比使用索引更快时(如查询结果包含整张表大部分数据),会放弃使用索引,直接进行全表扫描。例如一张表有 100 万行数据,若查询条件匹配了 80 万行,MySQL 可能选择全表扫描而非使用索引。

(6)示例

新建表,插入大量数据,通过无索引查询及有索引查询来对比性能

多次执行下述的自我复制,增加数据量(当增加到百万级时,后续查询耗时会变长)

插入新数据,并查询刚插入的数据

查看文件容量:

给 student 表新建索引,发现耗时变长了(0.08 sec)

在有索引的情况下再次查询,(花费时间会少于无索引耗时):

性能提升:

再次查看文件容量,对比建索引前,表容量增大:

总结:索引的本质就是以空间换时间,同时把随机的事件变成顺序的事件,日常项目开发中,读写比例在10:1左右,查询使用频率比较大,虽然损失点存储空间但两害取其轻,还是需要对关键字段新建索引提高查询性能

二、视图

1.视图介绍

MySQL 中的视图(view)是虚拟表,自身不包含数据,内容由查询定义。

数据来自定义视图时的基本表,打开视图时动态生成,类似复杂查询的"结果快照",可节省重复查询的资源。

2.需要视图原因

解决重复查询问题:例如频繁对 student 和 score 表进行连接查询时,可通过视图封装查询逻辑,避免重复编写语句。

实现数据安全控制:对敏感数据(如成绩数据),可通过视图隐藏不需要对外暴露的列或行。

3.视图作用和优点

(1)作用

控制安全:限制用户对数据的访问范围。

保存查询数据:封装常用的复杂查询逻辑。

(2)优点

简化操作:用户无需关心底层表的结构、关联和筛选条件,只需关注视图呈现的数据。

提高数据安全性:可为不同用户定义不同视图,仅开放其允许访问的结果集。

数据独立:视图结构定义后,底层表新增关系或字段不会影响用户对视图的访问。

4.创建视图

create [or replace] [algorithm = {undefined | merge | temptable}] view view_name [(column_list)] as select_statement [with [cascaded | local] check option]

说明:

or replace:如果要创建的视图名称已存在,则替换已有视图。

algorithm:可选参数,表示视图选择的算法,默认算法是 undefined

undefined:未定义指定算法

merge:更新视图表数据的同时会更新真实表的数据

temptable:只能查询不能更新

view_name:新建的视图名称。

column_list:可选,表示视图的字段列表。若省略,则使用 select 语句中的字段列表。

as select_statement:创建视图的 select 语句。

with check option:表示更新视图时要保证该视图的 where 子句为真。

总结:适用场景根据当前视图创建另一个视图时:

with local check option(只检查当前条件)

with cascaded check option(检查当前以及上一级的条件)

with check option(所有的条件都检查)

5.创建视图限制

(1)列名限制

不能使用 select * 语法来选择所有列。必须明确指定要选择的列,这样可以确保视图的结构清晰,并且在基表结构发生变化时,视图的定义不会受到意外影响。

列名必须是唯一的,不能有重复的列名。如果在 select 语句中使用了表达式或函数生成列,需要为其指定一个唯一的别名作为列名。(子查询需要更改列名)

(2)数据类型限制

视图中选择的列的数据类型通常不能进行随意转换或修改。如果基表中的列数据类型发生变化,可能会影响视图的查询结果或导致视图无法正常使用。

某些数据类型可能不适合在视图中使用,例如大对象数据类型(如BLOB、CLOB等),在视图中使用可能会导致性能问题或其他复杂性。

(3)查询语句限制

不能使用ORDER BY除非结合LIMIT

通常情况下,视图定义中的 select 语句不允许使用 order by 子句。因为视图本质上是一个虚拟表,排序操作应该在查询视图时进行。不过,如果 order by 与 limit 一起使用,MySQL 是允许的(有意义的)。

视图(View)定义里存在 order by 子句,而查询该视图的 SQL 语句里同样有 order by 子句时,最终的排序结果是由查询语句中的 order by 子句来决定的。

错误代码示例:

create view vw_employees as

select employee_id, first_name, last_name

from employees

order by employee_id;

正确代码示例:

create view vw_employees_limit as

select employee_id, first_name, last_name

from employees

order by employee_id

limit 10;

不能使用 group by子句,这些子句用于在查询结果中进行分组计算,不适合在视图定义中使用。

当使用连接查询来定义视图时,连接条件必须是明确和有效的,不能使用自连接或复杂的交叉连接方式,除非有明确的业务需求。

(4)权限限制

用户创建视图时,必须对 select 语句中引用的所有表或视图具有适当的查询权限。如果没有足够的权限,将无法成功创建视图。

视图的权限管理与基表是相互独立的。创建视图后,需要单独为用户或角色授予对视图的访问权限,即使用户对基表有访问权限,也不一定能够访问视图,反之亦然。

这些限制有助于确保视图的稳定性、性能和数据一致性,同时也遵循了视图作为一种数据抽象和查询工具的设计原则。不同的数据库管理系统可能会对视图的 select 语句有一些细微的差异和特定的限制,具体使用时需要参考相应的数据库文档

示例:

创建来源1张表的视图:

创建多表连接的视图:

创建视图,字段起别名:

6.更新视图

更新视图中的数据,实际上是更新创建视图时用到的基本表中的数据

以下视图不可更新:

包含以下关键字的 SQL 语句:聚合函数、distinct、group by 、having、union 或 uinon all

select 中包含子查询

from 一个不可更新的视图

where 子句的子查询引用了 from 子句中的表

示例:

视图中聚合函数不可更新:

对分组和having字段不可更新:

7.修改视图

示例:

通过 create or replace view 命令修改视图:

通过 alter view 命令修改视图:

8.删除视图

drop view [if exists] view_name;

示例:

9.导致视图表数据异常的行为

(1)视图本身并不存储数据,其数据来源于基表

(2)权限变更--没有查询权限

(3)基表数据类型变更

10.视图使用规则总结

视图必须有唯一命名

在mysql中视图的数量没有限制

创建视图必须从管理员那里获得必要的权限

视图支持嵌套,也就是说可以利用其他视图检索出来的数据创建新的视图

在视图中可以使用order by,但是如果视图内已经使用该排序子句,则视图的order by将覆盖前面的order by。

视图不能索引,也不能关联触发器或默认值

视图可以和表同时使用

相关推荐
朝新_11 小时前
【SpringMVC】详解用户登录前后端交互流程:AJAX 异步通信与 Session 机制实战
前端·笔记·spring·ajax·交互·javaee
TDengine (老段)11 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq74223498411 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE12 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy123931021612 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎12 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
是Yu欸12 小时前
【博资考5】网安2025
网络·人工智能·经验分享·笔记·网络安全·ai·博资考
杨云龙UP12 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql
l1t12 小时前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb
安当加密12 小时前
Nacos配置安全治理:把数据库密码从YAML里请出去
数据库·安全