diff --git "a/33\351\227\253\347\273\247\345\221\250/20231018\347\264\242\345\274\225.md" "b/33\351\227\253\347\273\247\345\221\250/20231018\347\264\242\345\274\225.md" new file mode 100644 index 0000000000000000000000000000000000000000..3c98f43c4146f19ed8e20d34f62004aea037525d --- /dev/null +++ "b/33\351\227\253\347\273\247\345\221\250/20231018\347\264\242\345\274\225.md" @@ -0,0 +1,203 @@ +**1、什么是MySQL索引?** +官方上面说索引是帮助MySQL高效获取数据的数据结构,通俗点的说,数据库索引好比是一本书的目录,可以直接根据页码找到对应的内容,目的就是为了加快数据库的查询速度。 +索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。 +一种能帮助mysql提高了查询效率的数据结构:索引数据结构。 +**1.1、索引原理** +索引的存储原理大致可以概括为一句话:以空间换时间。 + +一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。 + +数据库在未添加索引进行查询的时候默认是进行全文搜索,也就是说有多少数据就进行多少次查询,然后找到相应的数据就把它们放到结果集中,直到全文扫描完毕。 + +**1.2、索引的分类** +**主键索引:**primary key + +设定为主键后,数据库自动建立索引,InnoDB为聚簇索引,主键索引列值不能为空(Null)。 +**唯一索引**: + +索引列的值必须唯一,但允许有空值(Null),但只允许有一个空值(Null)。 +**复合索引:** + +一个索引可以包含多个列,多个列共同构成一个复合索引。 +**全文索引:** + +FullText(MySQL5.7之前,只有MYISAM存储引擎引擎支持全文索引)。 +全文索引类型为fulltext,在定义索引的列上支持值的全文查找允许在这些索引列中插入重复值和空值。全文索引可以在Char、VarChar 上创建。 +**空间索引:** + +MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型,MySQL在空间索引这方年遵循OpenGIS几何数据模型规则。 +**前缀索引:** + +在文本类型为char、varchar、text类列上创建索引时,可以指定索引列的长度,但是数值类型不能指定。 +**1.3、索引的优缺点** +**优点:** + +大大提高数据查询速度。 +可以提高数据检索的效率,降低数据库的IO成本,类似于书的目录。 +通过索引列对数据进行排序,降低数据的排序成本降低了CPU的消耗。 +被索引的列会自动进行排序,包括【单例索引】和【组合索引】,只是组合索引的排序需要复杂一些。 +如果按照索引列的顺序进行排序,对order 不用语句来说,效率就会提高很多。 +**缺点:** + +索引会占据磁盘空间。 +索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删改查操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。 +维护索引需要消耗数据库资源。 +**综合索引的优缺点:** + +数据库表中不是索引越多越好,而是仅为那些常用的搜索字段建立索引效果最佳! + +1.4、创建索引的基本操作 +创建主键索引: + +``` +#建表时,主键默认为索引 +create table user( + id varchar(11) primary key, + name varchar(20), + age int +) + +#查看user表中的索引 +show index from user; +``` + +在这里插入图片描述 + +创建单列索引: + +``` +#创建单列索引,只能包含一个字段 +create index name_index on user(name); +``` + +**在这里插入图片描述** + +创建唯一索引: + +``` +#创建唯一索引,只能有一个列 +create unique index age_index on user(age); +``` + +在这里插入图片描述 + +创建符合索引: + +``` +#复合索引 +create index name_age_index on user(name,age); +``` + +在这里插入图片描述 + +满足复合索引的查询的两大原则: +**假如创建的复合索引为三个字段,按顺序分别是(name,age,sex) +在查询时能利用复合索引的查询条件如下:** + +1、最左前缀原则(如下四种都满足条件) + +``` +select * from user where name = ? +select * from user where name = ? and age = ? +select * from user where name = ? and sex = ? +select * from user where name = ? and age = ? and sex = ? +``` + +1.1、如下是不满足最前左缀的条件(但是不是全部都不生效,如下第2原则解释) + +``` +select * from user where name = ? and sex = ? and age = ? +select * from user where age = ? and sex = ? and name = ? +select * from user where sex = ? and age = ? and name = ? +select * from user where age = ? and sex = ? +…………等等 +``` + +2.MySQL 引擎在执行查询时,为了更好地利用索引,在查询过程中会动态调整查询字段的顺序!(也就是说,当条件中的字段全部达到复合索引中的字段时,可以动态调整字段顺序,使其满足最前左缀) + +``` +#可以使用复合索引:索引中包含的字段数都有,只是顺序不正确,在执行的时候可以动态调整为最前左缀 +select * from user where sex = ? and age = ? and name = ? +select * from user where age = ? and sex = ? and name = ? +``` + +``` +#不可以使用复合索引:因为缺少字段,并且顺序不正确 + +select * from user where sex = ? and age = ? +select * from user where age = ? and name = ? +select * from user where age = ? +select * from user where sex = ? +``` + +3.2.4、最左匹配原则 +最左前缀匹配原则和联合索引的索引存储结构和检索方式是有关系的。 + +在组合索引树中,最底层的叶子节点按照第一列a列从左到右递增排序,但是b列和c列是无序的,b列只有在a列值相等的情况下小范围内有序递增;而clie只能在a和b两列值相等的情况下小范围内有序递增。 + +就像上面的查询,B+ 树会先比较a列来确定下一步应该检索的方向,往左还是往右。如果a列相同再比较b列,但是如果查询条件中没有a列,B+树就不知道第一步应该从那个节点开始查起。 + +可以说创建的idx_(a,b,c)索引,相当于创建了(a)、(a,b)、(a,b,c)三个索引。 + +组合索引的最左前缀匹配原则: + +使用组合索引查询时,mysql会一直向右匹配直至遇到范围查询(>、<、between、like)等就会停止匹配。 +3.2.5、覆盖索引 +==覆盖索引并不是一种索引结构,覆盖索引是一种很常用的优化手段==。因为在使用辅助索引的时候,我们只可以拿到相应的主键值,想要获取最终的数据记录,还需要根据主键通过主键索引再去检索,最终获取到符合条件的数据记录。 +在上面的abc_innodb表中的组合索引查询时,如果我们查询的结果只需要a、b、c这三个字段,那我们使用这个idx_index(a,b,c)组合索引查询到叶子节点时就可以直接返回了,而不需要再次回表查询,这种情况就是==覆盖索引==。 + +# 4、回表和联合索引的应用 + +## 4.1、回表查询 + +在InnoDB的存储引擎中,使用辅助索引查询的时候,因为辅助索引叶子节点保存的数据不是当前数据记录,而是当前数据记录的主键索引。如果需要获取当前记录完整的数据,就必须要再次根据主键从主键索引中继续检索查询,这个过程我们称之为**回表查询**。 + +由此可见,在数据量比较大的时候,回表必然会消耗很多的时间影响性能,所以我们要尽量避免回表的发生。 + +## 4.2、如何避免回表 + +使用覆盖索引,举个例子:现有User表 + +``` +CREATE TABLE `user` +( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` int(11) DEFAULT NULL, + `sex` char(3) DEFAULT NULL, + `address` varchar(10) DEFAULT NULL, + `hobby` varchar(10) DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + KEY `i_name` (`name`) +) ENGINE = InnoDB; +``` + +如果有一个场景: + +``` +select id,name,sex from user where name = 'zhangsan'; +``` + +这个语句在业务上频繁使用到,而user表中的其他字段使用频率远低于这几个字段,在这个情况下,如果我们在建立name字段的索引时,不是使用单一索引,而是使用`联合索引(name,sex)`,这样的话再执行这个查询语句,根据这个辅助索引`(name,sex)`查询到的结果就包括了我们所需要的查询结果的所有字段的完整数据,这样就不需要再次回表查询去检索sex字段的数据了。 + +> **以上就是一个典型的使用覆盖索引的优化策略减少了回表查询的情况。** + +## 4.3、联合索引的使用 + +**联合索引:** + +> 在建立索引的时候,尽量在多个单列索引上判断是否可以使用联合索引。联合索引的使用不仅可以节省空间,还可以更容易的使用到覆盖索引。 + +**节省空间:** + +> 试想一下,索引的字段越多,是不是更容易满足查询需要返回的数据呢?比如联合索引`(a,b,c)`是不是等于有了:`a`、`(a,b)`、`(a,b,c)`三个索引,这样是不是节省了空间,当然节省的空间并不是三倍于`a`、`(a,b)`、`(a,b,c)`三个索引所占用的空间,但是联合索引中data字段数据所占用的空间确实节省了不少。 + +**联合索引的创建原则:** + +> 在创建联合索引的时候应该把频繁使用的列、区分度高的列放在前面,频繁使用代表索引利用率高,区分度高代表筛选力度大,这些都是在创建索引的时候需要考虑到的优化场景,也可以将常需要作为查询返回的字段增加到联合索引中。 +> +> **如果在联合索引上增加了一个字段,而恰好满足了使用覆盖索引的情况,这种情况建议使用联合索引。** + +**联合索引的使用:** + +- 考虑到当前是否已经存在多个可以合并的单列索引,如果有,那么推荐将当前的多个单列索引创建为一个联合索引。 +- 当前索引存在频繁使用,在结果中有一个列也被频繁查询,而这个列不在当前频繁使用的索引中,那么这个时候就可以考虑这个列是否可以加入到当前频繁使用的索引中,使其查询语句可以使用到覆盖索引。 \ No newline at end of file