MYSQL高级-索引基础及七大JOIN

什么是MySQL索引

  • 索引是帮助MySQL高效获取数据的数据结构(有序的),可以理解为排好序的快速查找数据结构。
  • 在数据之外,数据库系统还维护着满足特定查找算法的数据结构这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法这种数据结构就是索引
  • 我们平常说的MySQL中的索引,没有特别指明的话,都是指BTree(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+TreeBTree的一种),统称索引。除了B+Tree这种类型的索引外,还有哈希索引等。
  • 一般来说,索引本身也挺大,不可能全部存储在内存中,因此,索引往往是以索引文件的形式存储在磁盘上的(.idx)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PnSoLBLx-1644828609425)(2021-11-26-MySQL中的索引.assets/image-20211126130332023.png)]

  • 分析上图

左边是数据表,一共有两列七条数据,最左边的十六进制数字代表他们的物理地址(逻辑上相邻,可是磁盘上并不一定相邻)。为了加快Col2的查找,可以维护一个右边所示的二叉查找树来加快数据的访问速度。

索引的优势和劣势

优势

  1. 类似于书籍的目录索引,提高了数据的检索效率,数据的检索,每一次遍历都得从磁盘读取到内存,而索引减少了遍历次数,所以索引降低了数据库的IO成本(影响WHERE)

  2. 通过索引列对数据进行排序降低数据排序的成本降低CPU的消耗(影响ORDER BY)

劣势

  1. 索引实质上也是一张表,该表保存了主键于索引字段,并指向实体类的记录,所以索引列也是要占用空间的,所以我们一般都放在磁盘而不是内存中
  2. 索引大大提高了查询效率,同时也降低了更新表的速度比如我们增删改,都会影响索引表中的对应关系。

索引的结构

索引他是在MySQL存储引擎层中实现的,不是在服务器层实现的。所以每种存储引擎的索引都不一定完全相同,同时不是所有的存储引擎都能支持所有的索引类型

  • BTREE索引:最常见的索引类型,大部分的存储引擎都支持,在MySQLInnoDB引擎中是BTREE结构下的 B+Tree 索引结构。
  • HASH索引:使用场景简单。
  • R-tree索引(空间索引):空间索引是MylSAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少。
  • Full-text(全文索引):全文索引也是MyISAM的一个特殊所以类型,主要用于全文索引,InnoDB引擎从MySQL5.6版本开始支持。

MySQL提供的四种索引

索引结构InnoDB引擎(主要)MyISAM引擎Memory引擎
BTREE索引支持支持支持
HASH索引支持不支持支持
R-tree索引不支持支持不支持
Full-text5.6版本后支持支持不支持

所以我们常说的索引,没有特别指明的话,基本都是指B+树(多路索引树,并不一定是二叉结构)结构组织的索引。其中,聚集索引复合索引前缀索引唯一索引默认都是使用B+tree索引,统称为索引

BTREE结构(重点)

BTree又叫做多路平衡搜索树,一棵m叉的BTree特性如下:

  • 树中每个节点最多包含m个孩子
  • 除根节点与叶子节点外,每个结点至少含有==ceil(m/2)==个孩子。
  • 根节点不是叶子节点则至少有两个孩子
  • 所有叶子节点都在同一层
  • 每个非叶子节点n个keyn+1个指针 组成,其中==ceil(m/2) - 1 <= n <=m-1==,所谓的指针域,就在下面的例子中的每一路的第二行空行。
  • 指针代表要走哪条路

5叉的BTree为例,key的数量:公式推导 ceil(m/2) - 1 <= n <= m-1。所以 2 <= n <= 4当 n > 4 时,中间结点分裂到父节点两边结点分裂

用插入 C N G A H E K Q M F W L T Z D P R X Y S 数据为例来说明:

演变的过程如下:

1). 插入前4个字母 C N G A ,按ASSIC码大小排序,2 <= n <= 4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILTxpyGT-1644828555729)(2021-11-26-MySQL中的索引.assets/image-20211126130804700.png)]

2). 插入Hn > 4触发分裂阈值,中间元素G字母向上分裂到新的节点

在这里插入图片描述

3). 插入E K Q不需要分裂,因为都在 n 的范围内

在这里插入图片描述

4). 插入M,中间元素M字母向上分裂到父节点G,在这里我们就可以看出为什么每一路指针要有 n + 1 个的原因了

在这里插入图片描述

5). 插入F W L T不需要分裂

在这里插入图片描述

6). 插入Z中间元素T向上分裂到父节点中

在这里插入图片描述

7). 插入D中间元素D向上分裂到父节点中。然后插入P,R,X,Y不需要分裂,注意每插一个就要进行一次是否分裂的判断

在这里插入图片描述

8). 最后插入SN P Q R 这一路节点 n > 5中间节点Q向上分裂,但分裂后父节点 D G M Tn > 5中间节点M向上分裂

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YCkDjHLT-1644828555731)(2021-11-26-MySQL中的索引.assets/image-20211126130908282.png)]

到此,该BTREE树就已经构建完成了, 我们可以看出,由于层数的原因,BTREE树 和 二叉树 相比, 查询数据的效率更高因为对于相同的数据量来说BTREE的层级结构比二叉树小,因此搜索速度快。

B+TREE

B+TreeBTree的变种,B+TreeBTree的区别:

  • m叉B+Tree 最多含有 m个key, 而 BTree 最多含有 m-1个key
  • B+Tree叶子节点保存所有的 key 信息,按key大小顺序排列
  • 所有的非叶子节点都可以看作是key的索引部分

在这里插入图片描述

由于B+Tree只有叶子节点保存key信息查询任何key都要从root走到叶子。所以B+Tree的所以==查询效率更加稳定==。

MySQL中的B+Tree

MySQL中的索引数据结构对经典的B+Tree进行了优化。在原来的基础上,增加了一个指向相邻叶子节点的链表指针,形成了带有顺序的 B+Tree这么做的好处就是提高了区间访问的新能

MySQL中的 B+Tree 索引结构示意图::

在这里插入图片描述

怎么个提高法,我们可以拿想要查找17,由于有指针的存在,我们可以快速定位区间,直接从 15结点 开始查找就行了,极大的减少了定位的时间复杂度。

索引的分类(重要)

  1. 单值索引:一个索引只包含单个列,一个表可以有多个单列索引,中规中矩的建议一张表最多五个单值索引索引值可多次出现
  2. 唯一索引索引列的值必须唯一但允许为空
  3. 复合索引:一个索引包含多个列。

索引的语法(重要)

索引可以与表同时创建,也可以随时增加,在MySQL中主键字段,会自动创建主键索引

索引一共有四种创建方式:唯一索引,主键索引,单值索引,全文索引四种。

准备环境

CREATE TABLE `city` (
  `city_id` int(11) NOT NULL AUTO_INCREMENT,
  `city_name` varchar(50) NOT NULL,
  `country_id` int(11) NOT NULL,
  PRIMARY KEY (`city_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `country` (
  `country_id` int(11) NOT NULL AUTO_INCREMENT,
  `country_name` varchar(100) NOT NULL,
  PRIMARY KEY (`country_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into `city` (`city_id`, `city_name`, `country_id`) values(1,'西安',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(2,'纽约',2);
insert into `city` (`city_id`, `city_name`, `country_id`) values(3,'北京',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(4,'上海',1);
insert into `city` (`city_id`, `city_name`, `country_id`) values(5,'伦敦',4);
insert into `city` (`city_id`, `city_name`, `country_id`) values(6,'东京',3);
insert into `city` (`city_id`, `city_name`, `country_id`) values(7,'大阪',3);
insert into `city` (`city_id`, `city_name`, `country_id`) values(8,'华盛顿',2);

insert into `country` (`country_id`, `country_name`) values(1,'中国');
insert into `country` (`country_id`, `country_name`) values(2,'美国');
insert into `country` (`country_id`, `country_name`) values(3,'日本');
insert into `country` (`country_id`, `country_name`) values(4,'英国');

创建索引

语法:

CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name 
[USING index_type] -- 选择索引分类,不指定默认使用 B+Tree 类型
ON tbl_name(index_col_name, ...) -- 哪一张表的哪个字段,两个以上就是符合索引

index_col_name : column_name[(length)][ASC | DESC]

city 表中用 city_name 创建一个普通索引

CREATE INDEX `index_city_name `
ON city(city_name);

查看索引

语法:

SHOW INDEX FROM tbl_name;

查看 city 表所持有的索引:

这里会打印出我们刚刚创建的索引以及主键索引共两个索引。

SHOW INDEX FROM `city`;

删除索引

语法:

DROP INDEX index_name ON tbl_name;

我们删除创建的 index_city_name 索引:

DROP INDEX `index_city_name` ON `city`;

ALTER命令

ALTER 来创建或修改索引。

语法:

-- 添加一个主键,这意味着索引的值必须唯一,并且不能为空
ALTER TABLE tbl_name ADD PRIMARY KEY(column_list);
-- 创建索引的值必须是唯一的(比如国家的名称就不可能重复),可以为空
ALTER TABLE tbl_name ADD UNIQUE index_name(column_list);
-- 创建普通索引,值可以出现多次
ALTER TABLE tbl_name ADD INDEX index_name(column_list);
-- 创建全文索引
ALTER TABLE tbl_name ADD FULLTEXT index_name(column_list);

索引的设计原则(重要)

  • 索引字段的选择,最佳候选列应该是 where子句常用的条件,如果 where子句 中的条件组合比较多应该挑选最常用并且过滤效果相对最好的组合
  • 使用唯一索引,区分度越高,使用索引的效率越高。
  • 索引数量不是越多越好,索引越多,维护的代价越高:
    • 对于增删改等DML ** 操作频繁的表来说,索引过多会提升维护成本**,从而降低增删改等DML操作的效率
    • 对于MySQL来说,也不是越多越好,索引多了就得选择,选择的过程也会消耗时间。
  • 使用短索引,索引建立之后是使用硬盘来存储的:
    • 提升索引访问I/O操作效率,也可以提升总体的访问效率
    • 如果构成索引的字段总长度比较短的话,在给定大小的存储块内可以存储更多的索引,就可以提升MySQL访问索引的 I/O 操作的效率。
  • 利用最左前缀N个列组合而成的组合索引那么相当于是创建了N个索引,如果查询时 where子句 中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率
  • 例如:
CREATE INDEX index_person_name_tel_email 
ON person(person_name, person_tel, person_email);
-- 相当于对 person_name 创建了索引
-- 同时也对 person_name, person_tel 创建了索引
-- 说白了就是对 person_name, person_tel, person_email 的笛卡尔积中的所有元素都做了索引

什么情况建议建立索引

  • 主键自动建立唯一索引。
  • 查询频率较高,并且数据量较大的表建立索引
  • 查询中与其它表的关联字段外键关系建立索引
  • WHERE条件用不到的字段不创建索引
  • 单值索引/组合索引的选择问题:
    • 高并发下,建议选择组合索引
  • 最常查询,最常进行排序的字段
    • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度。
    • 查询中,统计或者分组字段,分组前提是排序。

什么情况不建议建立索引

  • 表记录的数据很少的时候。
    • MySQL三百万数据之后不建索引检索效率会下降。
  • 频繁更新的字段不适合创建索引,提高查询速度降低更新速度
  • 数据重复,且分布平均的表字段,重复内容过多,索引效果越低

JOIN查询

常见的查询

针对上方第四个原因来系统了解一下join查询。

重温DQL的语法:

# 人工
SELECT DISTINCT
	<select_list>
FROM
	<left_table> <join_type>
JOIN <right_table> ON <join_condition>
WHERE
	<where_condition>
GROUP BY
	<group_by_list>
HAVING
	<having_condition>
ORDER BY
	<order_by_condition>
LIMIT <limit_number>
# 机读
FROM <left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>

| 在这里插入图片描述

机读顺序

七大JOIN查询

|在这里插入图片描述

七大JOIN查询(Oracle)

测试案例

CREATE TABLE t_dept(
	id INT(11) NOT NULL AUTO_INCREMENT,
	deptName VARCHAR(30) DEFAULT NULL,
	locAdd VARCHAR(40) DEFAULT NULL,
	PRIMARY KEY(id)
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE t_emp (
	id INT(11) NOT NULL AUTO_INCREMENT,
	NAME VARCHAR(20) DEFAULT NULL,
	deptId INT(11) DEFAULT NULL,
	PRIMARY KEY (id),
	KEY fk_dept_Id (deptId)
	#CONSTRAINT 'fk_dept_Id' foreign key ('deptId') references 'tbl_dept'('Id')
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO t_dept(deptName,locAdd) VALUES('RD',11);
INSERT INTO t_dept(deptName,locAdd) VALUES('HR',12);
INSERT INTO t_dept(deptName,locAdd) VALUES('MK',13);
INSERT INTO t_dept(deptName,locAdd) VALUES('MIS',14);
INSERT INTO t_dept(deptName,locAdd) VALUES('FD',15);

INSERT INTO t_emp(NAME,deptId) VALUES('z3',1);
INSERT INTO t_emp(NAME,deptId) VALUES('z4',1);
INSERT INTO t_emp(NAME,deptId) VALUES('z5',1);
INSERT INTO t_emp(NAME,deptId) VALUES('w5',2);
INSERT INTO t_emp(NAME,deptId) VALUES('w6',2);
INSERT INTO l_emp(NAME,deptId) VALUES('s7',3);
INSERT INTO t_emp(NAME,deptId) VALUES('s8',4);
INSERT INTO t_emp(NAME,deptId) VALUES('s9',51);
+----+----------+--------+
| id | deptName | locAdd |
+----+----------+--------+
|  1 | RD       | 11     |
|  2 | HR       | 12     |
|  3 | MK       | 13     |
|  4 | MIS      | 14     |
|  5 | FD       | 15     |
+----+----------+--------+
5 rows in set (0.00 sec)

+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
|  1 | z3   |      1 |
|  2 | z4   |      1 |
|  3 | z5   |      1 |
|  4 | w5   |      2 |
|  5 | w6   |      2 |
|  6 | s8   |      4 |
|  7 | s9   |     51 |
+----+------+--------+
7 rows in set (0.00 sec)
  • join类型一
    在这里插入图片描述

  • join类型二

    • 查询结果中有左表的所有条目包含两表交叉部分
    • 左表独有部分,在右表中有就显示,没有就补null
      在这里插入图片描述
  • join类型三

    • 查询结果中有右表的所有条目包含量表交叉部分
    • 右表独有部分,在左表中有就显示,没有就null
      在这里插入图片描述
  • join类型四

    • 查询结果有左表独有的内容右表同行为空

在这里插入图片描述

  • join类型五

    • 查询结果有右表独有的内容左表同行为空
      在这里插入图片描述
  • join类型六

    • 查询结果是全方位,左右表公有、私有部分都有
    • 图中语法,MySQLSQL 并不支持,只能用 UNION 来联合实现。

在这里插入图片描述

  • join类型七
    • 左表右表私有部分
      在这里插入图片描述

码云仓库同步笔记,可自取欢迎各位star指正:https://gitee.com/noblegasesgoo/notes

如果出错希望评论区大佬互相讨论指正,维护社区健康大家一起出一份力,不能有容忍错误知识。
										—————————————————————— 爱你们的 noblegasesgoo
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
索引是一种数据结构,它可以帮助加快数据库表中数据的检索速度。在 MySQL 数据库中,索引通常被称为 B-tree 索引,它可以加速 SELECT、UPDATE 和 DELETE 操作的速度。在本文中,我们将介绍 MySQL 中的索引,包括索引的类型、如何创建索引、如何使用索引以及索引的优化。 ## 索引的类型 MySQL 支持多种类型的索引,包括以下几种常见的类型: - PRIMARY KEY 索引:用于唯一标识数据库表中的每一行记录。 - UNIQUE 索引:用于确保表中某一列的值是唯一的。 - INDEX 索引:用于加速表中的数据检索操作。 - FULLTEXT 索引:用于全文搜索操作。 ## 如何创建索引MySQL 中,可以使用 CREATE INDEX 语句来创建索引。例如,下面的语句创建一个名为 idx_last_name 的索引,用于加速对 employees 表中 last_name 列的检索: ``` CREATE INDEX idx_last_name ON employees (last_name); ``` 需要注意的是,创建索引可能会增加数据库表的插入、更新和删除操作的时间开销。因此,应该谨慎地考虑是否需要创建索引,以及应该创建哪些索引。 ## 如何使用索引MySQL 中,可以使用 EXPLAIN 语句来查看查询语句的执行计划。如果查询语句使用了索引,则在执行计划中会显示使用的索引名称。例如,下面的语句使用 EXPLAIN 来查看对 employees 表进行 last_name 列检索的执行计划: ``` EXPLAIN SELECT * FROM employees WHERE last_name = 'Smith'; ``` 如果查询语句没有使用索引,则可以使用 FORCE INDEX 语句来强制使用指定的索引。例如,下面的语句强制使用 idx_last_name 索引来对 employees 表进行 last_name 列检索: ``` SELECT * FROM employees FORCE INDEX (idx_last_name) WHERE last_name = 'Smith'; ``` 需要注意的是,强制使用索引可能会导致性能下降。因此,应该仅在必要时使用强制索引。 ## 索引的优化 在 MySQL 中,可以使用 OPTIMIZE TABLE 语句来优化数据库表。优化表可以帮助减少表中的碎片,提高表的查询性能。例如,下面的语句优化 employees 表: ``` OPTIMIZE TABLE employees; ``` 此外,还可以使用 ANALYZE TABLE 语句来分析表中的数据分布情况,以便优化索引。例如,下面的语句分析 employees 表的数据分布情况: ``` ANALYZE TABLE employees; ``` 需要注意的是,索引的性能可能会受到数据分布的影响。如果表中的数据分布不均匀,则可能需要重新设计索引或优化查询语句以提高性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值