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。

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

视图可以和表同时使用

相关推荐
维尔切2 小时前
MySQL 主从复制
linux·运维·数据库·mysql·adb
wow_DG2 小时前
【MySQL✨】MySQL 入门之旅 · 第十一篇:MySQL 表连接(JOIN)基础
数据库·mysql
BullSmall3 小时前
Kafka 图形界面客户端工具
笔记·kafka
程序视点3 小时前
MySQL存储引擎InnoDB vs. MyISAM,技术选型如何判断?
mysql
sun_qqq3 小时前
数据可视化的中间表方案
数据库·mysql·数据分析·数据库开发·数据可视化
码界筑梦坊3 小时前
269-基于Python的58同城租房信息数据可视化系统
python·mysql·信息可视化·数据分析·flask·毕业设计·echarts
马克学长3 小时前
SSM滁州学院考研信息分享论坛0iaj2 (程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·考研·ssm
安得权3 小时前
Ubuntu18.04 MySQL5.7.42 内存升高导致OOM MySQL重启解决办法
mysql
先做个垃圾出来………4 小时前
Pydantic库应用
java·数据库·python