Mysql调优实践1

news/2024/11/15 1:01:16/文章来源:https://www.cnblogs.com/purearc/p/18430396

第一章 索引

1.什么是索引

​ 提到索引,我们想到的是查询慢了设置索引呗!但是索引为什么起作用?设置了索引为什么还是慢我们其实不是很清楚。在关系数据中,索引是一种数据结构,他将数据提前按照一定的规侧进行排序和组织,能够帮助快速定位到数据记录的数据,加快数据库表中数据的查找和访问速度。像书籍的目录、文件夹、标签、房号…都可以帮助我们快速定位,都可以视为索引。能实现快速定位数据的一种存储结构,其设计思想是以空间换时间。

2.索引的种类

不同存储引擎不同的索引类型和实现

按照数据结构:B+ tree索引、Hash索引、full-text索引

按照物理存储:聚集索引、非聚集索引

按照字段特性:主键索引(PRIMARY KEY)、唯一索引(UNIQUE)、普通索引(INDEX)、全文索引(FULLTEXT)

按照字段个数:单列索引、联合索引(复合索引/组合索引)

3.按照数据结构分类索引

二叉树、红黑树、B树、B+树
区别:树的高度影响获取数据的性能(每一个树节点都是一次磁盘/O)

二叉树

特点:每个节点最多两个子节点,大在左,小在右,数据随机性情况下树杈越明显

image-20240924002636397

如果数据是按顺序依次进入:
树的高度则会很高(就是一个链表结构),此时元素的查找效率就等于链表查询O(),数据检索效率将极为低下。

image-20240924002705383

极端的情况下就是一个链表结构(如上图),此时元素的查找效率就等于链表查询O(n)

红黑树(平衡二叉树)

​ 通过自旋平衡,子节点会自动分叉为2个分支,从而减少树的高度,当数据有序插入时比二叉树数据检索性能更佳。但是如果数据量过大,节点个数就越多,树高度也会增高(也就是树的深度越深),增加磁盘1/O次数,影响查询效率。

image-20240924003018811

B-树

​ B树的出现可以解决树高度的问题。之所以是B树,而并不是名称中”XX二叉树",就是它不再限制一个父节点中只能有两个子节点,而是允许M个子节点(M>2)。不仅如此,B树的一个节点可以存储多个元素,相比较于前面的那些二叉树数据结构又将整体的树高度降低了。

​ 最多有几个分支 -> 阶 一个节点最多存储 阶数-1 个数据,超出就会上升成父节点

​ mysql -> 16阶的B+树 -> 一个节点最多15个元素

image-20240924003453778

​ 对范围的查找支持比较差 -> 每次都回到根节点查找

B+-树

​ B+tree是在B树基础上的一种优化,其更适合做存储索引结构。在B+tree中,非叶子节点上仅存储键值,不存储数据;而所有数据记录均存储在叶子节点上,并且数据是按照顺序排列的。此外在B+tree中各个数据页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的。B+tree的结构图如下:

​ 所有数据在叶子节点

​ 非叶子节点不妨数据

​ 叶子节点上有双向指针

image-20240924003925319

Hash索引

​ Hash索引其实用的不多,最主要是因为最常见的存储引擎InnoDB不支持显示地创建Hash索引,只支持自适应Hash索引。虽然可以使用sql语句在InnoDB显示声明Hash索引,但是其实是不生效的。

image-20240924004432544

​ 对name字段建立Hash索引,但是通过show index from表名就会发现实际还是B+树

image-20240924004454079

​ 在存储引擎中,Memory引擎支持Hash索引。Hash索引其实有点像Java中的HashMap底层的数据结构,他也有很多的槽,存的也是键
值对,键值为索引列,值为数据的这条数据的行指针,通过行指针就可以找到数据.

​ 假设现在user表用Memory存储引擎,对name字段建立Hash索引,表中插入三条数据

image-20240924004513090

​ Hash索引会对索引列name的值进行Hash计算,然后找到对应的槽下面,如下图所示

image-20240924004635440

​ 当遇到name字段的Hash值相同时,也就是Hash冲突,就会形成一个链表,比如有name=张三有两条数据,就会形成一个链表。之后如果要查name=李四的数据,只需要对李四进行Hash计算,找到对应的槽,遍历链表,取出name=李四对应的行指针,然后根据行指针去查找对应的数据。

4.按照物理存储分类索引

按物理存储分类:InnoDB的存储方式是聚集索引,MyISAM 的存储方式是非聚集索引。

聚簇索引:数据本身和索引放在同一个文件中。

image-20240924005011893

非聚簇索引:数据本身和索引放在不同的两个文件中。

image-20240924005252535

4.1二级索引

除了主键的索引都是二级索引

​ 在MySQL中,创建一张表时会默认为主键创建聚簇索引,B+树将表中所有的数据组织起来,即数据就是索引主键所以在InnoDB里,主键索引也被称为聚簇索引,索引的叶子节点存的是整行数据。而除了聚簇索引以外的所有索引都称为二级索引,二级索引的叶子节点内容是主键的值。

CREATE TABLE
users(id INT NOT NULL,name VARCHAR(20)NOT NULL,age INT NOT NULL,PRTMARY KEY(id)
)
#新建一个以age字段的二级索引:
ALTER TABLE users ADD INDEX(index age(age);
#MySQL会分别创建主键id的聚簇索引和age的二级索引:

image-20240924005423422

4.2回表

​ 讲完二级索引,接下来讲一讲如何使用二级索引查找数据。这里假设对name字段创建了一个索引,并且表里就存了上面示例中的几条数据,例如执行下面这条sq则需要进行回表:

SELECT * FROM users WHERE age = 35;

image-20240924005726530

由于查询条件是name=赵六,所以会走name索引,整个过程大致分为以下几个步骤:

​ 从根节点开始,21<35定位右边存储指针

​ 在索叶子节点找到35的第一条记录,也就是id=9的那条

​ 由于是select*,·还要查其它字段,此时就会根据id=9到聚簇索引(主键索引)中查找其它字段数据,这个查找过程前面说了很多次了,这个根据id=4到聚簇索引中查找数据的过程就被称为回表。

4.3回表的应用——覆盖索引

上一节说当执行select * from user where age=35;这条sql的时候,会先从索引页中查出来age=35对应的主键 id 之后再回表,到聚簇索引中查询其它字段的值,那么当执行下面这条sql,又会怎样呢?

select id from user where age 35;

image-20240924005951612

​ 所以还是跟前面一样了,先从索引页中查出来age=35对应的主键 id 之后,惊讶的发现,sql 中需要查询字段的 id 值已经查到了,那此时压根就不需要回表了,已经查到 id 了,还回什么表。而这种需要查询的字段都在索引列中的情况就被称为覆盖索引,索引列覆盖了查询字段的意思。
​ 当使用覆盖索引时会减少回表的次数,这样查询速度更快,性能更高。所以,在日常开发中,尽量不要select *,需要什么查什么,如果出现覆盖索引的情况,查询会快很多。

4.4回表的优化——索引下推

​ 索引下推( INDEX CONDITION PUSHDOWN,简称ICP ) 是在MySQL5.6针对扫描二级索引的一项优化改进。用来在范围查询时减少回表的次数。ICP 适用于 MYISAM 和 INNODB。

ALTER TABLE `test'.`user` ADDINDEX (`name`,`age`)

不使用索引下推实现:

每查一条就回表一次

image-20240924010403445

image-20240924010314922

使用索引下推实现

image-20240924010342373

Explain SELECT * FROM user1 WHERE name LIKE `A%` and age = 40;

image-20240925002015391

image-20240925002022139

接下来执行如下的 sql:

select * from `user` where name > `王五` and age > 22;

在MySQL5.6(不包括5.6)之前,整个 sql 大致执行步骤如下:

​ 1)先根据二分查找,定位到name>'王五'的第一条数据,也就是id=4的那个赵六

​ 2)之后就会根据id=4进行回表操作,到聚簇索引中查找id=4其它字段的数据,然后判断数据中的age是否大于22,是的话就说
明是我们需要查找的数据,否则就不是

​ 3)之后顺着链表,继续遍历,然后找到一条记录就回一次表,然后判断age,如此反复下去,直至结束

​ 所以对于图上所示,整个搜索过程会经历5次回表操作,两个赵六,两个刘七,一个王九,最后符合条件的也就是id=6赵六
条数据,其余age不符和。

​ 虽然这么执行没什么问题,但是不知有没有发现其实没必要进行那么多次回表,因为光从上面的索引图示就可以看出,符合name>'王五 ' and age>22的数据就id=6的赵六那条数据所以在MySQL5.6之后,对上面的age>22判断逻辑进行了优化:

​ 前面还是一样,定位查找到id=4的那个赵六,之后就不回表来判断age了,因为索引列有age的值了,那么直接根据索引中age
断是否大于22,如果大于的话,再回表查询剩余的字段数据(因为是select*),然后再顺序链表遍历,直至结束所以这样优化之后,回表次数就成1了,相比于前面的5次,大大减少了回表的次数。而这个优化,就被称为索引下推,就是为了减少回表的次数。

​ 之所以这个优化叫索引下推,其实是跟判断age > 22逻辑执行的地方有关,这里就不过多赘述了。

4.5回表的优化——索引合并

​ 索引合并 ( index merge ) 是从MySQL5.1开始引入的索引优化机制,在之前的 MySQL 版本中,一条 sql 多个查询条件只能使用一
个索引,但是引入了索引合并机制之后,MySQL在某些特殊的情况下会扫描多个索引,然后将扫描结果进行合并。

​ 结果合并会为下面三种情况:

​ 1)取交集(intersect)

​ 2)取并集(union)

​ 3)排序后取并集(sort-union)

为了不耽误演示,删除之前所有的索引,然后为nameage各自分别创建一个二级索引idx_nameidx_age

取交集(intersect)

当执行下面这条sq就会出现取交集的情况

select * from `user` where name = `赵六` and age = 22;

查看执行计划

image-20240925003301280

typeindex merge,并且possible keykey都是idx nameidx age,说明使用了索引合并,并且ExtraUsing intersect(idx age,idx name)intersect就是交集的意思。

​ 整个过程大致是这样的,分别根据idⅸnameidx age取出对应的主键id,之后将主键id取交集,那么这部分交集的id一定同时满
足查询ame='赵六' and age=22的查询条件(仔细想想),之后再根据交集的id回表。不过要想使用取交集的联合索引,需要满足各自索引查出来的主键id是排好序的,这是为了方便可以快速的取交集。

​ 比如下面这条sq就无法使用联合索引:

select * from `user`where name = `赵六` and age > 22;

image-20240925003608749

​ 只能用name这个索引,因为age>22查出来的id是无序的,前面在讲索引的时候有说过索引列的排序规则,由此可以看出,使用联合索引条件还是比较苟刻的。

取并集(union)

取并集就是将前面例子中的and换成or

select * from `user` where name = `赵六`  or age > 22;

​ 前面执行的情况都一样,根据条件到各自的索引上去查,之后对查询的取并集去重,之后再回表。同样地,取并集也要求各自索引查出来的主键id是排好序的,如果查询条件换成age>22时就无法使用取并集的索引合并。

排序后取并集(sort-union)

​ 虽然取并集要求各自索引查出来的主键id是排好序的,但是如果遇到没排好序的情况,mysql 会自动对这种情况进行优化,会先
对主键id排序,然后再取并集,这种情况就叫排序后取并集(sort-union)。

比如上面提到的无法直接取并集的sql就符合排序后取并集(sort-union)这种情况

select from 'user' where name =` 赵六` or age > 22`;

5.按照字段个数分类索引

5.1单列索引

ALTER TABLE `test`.`user` ADD INDEX(`name`);

​ 假设,我们现在对name字段加了一个普通非唯一索引,那么name就是索引列,同时name这个索引也就是单列索引,此时如果往表中插入三条数据,那么name索引的叶子节点存的数据就如下图所示:

image-20240924235236428

​ mysql会根据name字段的值进行排序,这里我假设张三排在李四前面,当索引列的值相同时,就会根据id排序,所以索引实际
上已经根据索引列的值排好序了。
​ 这里肯定有小伙伴疑问,name字段存储的中文也可以排序么?答案是可以的,并且 mysql 支持很多种排序规侧,我们在建数据库或是建表的时候等都可以指定排序规则,并且后面文章涉及到的字符串排序都是我随便排的,实际情况可能不一样。

image-20240924235400394

​ 对于单个索引列数据查找也是跟前面说的聚簇索引一样,也会对数据分组,之后可以根据二分查找在单个索引列来查找数据。当数据不断增多,一个索引页存储不下数据的时候,也会用多个索引页来存储,并且索引页直接也会形成双向链表。

image-20240924235431656

​ 当索引页不断增多时,为了方便在不同索引页中查找数据,也就会抽取一个索引页,除了存页中 id ,同时也会存储这个 id 对应索引列的值。

image-20240924235537302

​ 当数据越来越多越来越多,还会抽取,也会形成三层的一个B+树,这里我就不画了。

5.2联合索引

ALTER TABLE `test`.`use`r ADD INDEX(`name`,`ag`e,`id`);

​ 除了单列索引,联合索引其实也是一样的,只不过索引页存的数据就多了一些索引列。比如,在nameage上建立一个联合索引,此时单个索引l页就如图所示:

image-20240924235738709

​ 先以name排序,name相同时再以age排序,如果再有其它列,依次类推,最后再以id排序。相比于只有name一个字段的索引来说,索引页就多存了一个索引列。最后形成的B+树简化为如下图:

image-20240924235816468

5.3最左前缀原则

​ 顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上。如果没有第一列的话,直接访问第二列,那第二列肯定是无序的,直接访问后面的列就用不到索引了当创建(a,b,c)复合索引时,想要索引生效的话,只能使用aabacabc三种组合

面试问:使用acb索引会不会生效?为什么(这个真被问过)。

第二章 优化

1.优化方法

image-20240924011452581

​ 上图所示的金字塔,从下往上列了4个查询的优化手段,依次是:SQL及索引优化、库表结构优化、系统配置优化、硬件优化。对于单个 MySQL 来讲,从下往上优化,成本是逐步提升的,但效果反而越来越差。通常来说,SQL及索引调优往往
不需要花费过多成本,却可以取到显著效果。

关于SQL优化方法,包括5点
1)创建索引减少扫描量;

​ 2)调整索引减少计算量;

​ 3)索引覆盖(减少不必访问的列,避免回表查询);

​ 4)干预执行计划;

​ 5)SQL改写;

2.通过Explain干预执行计划

3.SQL改写

准备工作

创建 student 表

image-20240925004519620

创建 scores 表

image-20240925004538577

添加索引

image-20240925004549830

插入数据

image-20240925004600620

image-20240925004620567

3.1 避免使用SELECT *

image-20240925005052961

​ 查看执行计划,select *走全表扫描,没有用到任何索引,查询效率非常低;查询列都是索引列那么这些列被称为覆盖索引。这种情况下查询的相关字段都能对索引,索引查询的效率相对较高。

image-20240925005211695

​ 通过show warnings语句查看查询列*号替换成表所有字段。

image-20240925005305662

总结:

​ 查询时需要先将星号解析成表的所有字段然后在查询,增加查询解析器的成本;

select*查询一般不走覆盖索引会产生大量的回表查询;

​ 在实际应用中我们通常只需要使用某几个字段,其他不需要使用的字段也查出来浪费CPU、内存资源;

​ 文本数据、大字段数据数据传输增加网络消耗。

3.2 小表驱动大表

小表驱动大表就是指用数据量较小、索引比较完备的表,然后使用其索引和条件对大表进行数据筛选,从而减少数据计算量,提高查询效率。比如说student表有30条数据,scores表有80w条数据。

image-20240925005427923

image-20240925005443883

Join Buffer(连接缓冲区)是优化器用于处理连接查询操作时的临时缓冲区。简单来说当我们需要比较两个或多个表的数据进行join操作时,Join Buffert可以帮助 MySQL 临时存储结果,以减少磁盘读取和 CPU 负担,提高查询效率。需要注意的是每个join都有一个单独的缓冲区。

Block nested-loop join(BNL算法)会将驱动表数据加载到join buffer里面,然后再批量与非驱动表进行匹配;如果驱动表数据量较大,join buffer无法一次性装载驱动表的结果集,将会分阶段与被驱动表进行批量数据匹配,会增加被驱动表的扫描次数,从而降低查询效率。所以开发中要遵守小表驱动大表的原则。

​ 分阶段匹配过程如下:

​ 1)先把student表前15条数据读到join buffer中。

​ 2)然后用scores表去匹配join buffer中的前15条。

​ 3)记录下匹配结果。

​ 4)清空join buffer。

​ 5)再把student表后15条读取join buffert中。

​ 6)然后用scores表去匹配join buffer中的后15条。

​ 7)记录下匹配结果

3.3用连接查询代替子查询

​ mysql 需要在两张表以上获取数据的方式有两种:第一种通过连表查询获取,第二种通过子查询获取。

​ 模拟一个真实场景,同样student表有30条数据,scores表有80w条数据,我们想查看学号小于15的学员各科分数信息:

image-20240925005731819

​ 因为子查询需要执行两次数据库查询,一次是外部查询,一次是嵌套子查询。因此,使用连接查询可以减少数据库查询的次数,提高查询的效率。

​ 连接查间可以更好地利用数据库索引,提高查间的性能。子查间通常会使用临时表或内存表,而连接查询可以直接利用表上的索引。这意味着连接查间可以更快地访问表中的数据,减少查间的资源消耗。对于大型数据集,使用连接查询通常比使用子查询更高效。子查询通常需要扫描整个表,而连接查询可以利用索引加速读取操作。

image-20240925005817756

​ 使用连接查询可以更快地执行查间操作,减少数据库的负载,提高查询的性能和效率。

3.4提升GroupBy效率

​ 创建索引:如果你使用group by的列没有索引,那么查询可能会变得很慢。因此,可以创建一个或多个适当的索引来加速查询。

image-20240925005932848

​ 添加索引前:

image-20240925005947212

​ 添加索引后:

image-20240925010000389

​ 调整查询:查询的写法也会影响group by的效率。可以尝试不使用子查询或临时表,或者可以使用JOINEXISTS来代替IN子查询。

​ 限制结果集的数量:如果你只需要查看一小部分结果,可以在查询中添加LIMIT子句,以便只返回一定数量的结果。

3.5批量操作

​ 批量插入或批量删除数据,比如说现在需要将1W+数据插入到数据库,大家是一条一条处理还是批量操作呢?建议是批量操作,逐个处理会频繁的与数据库交互,损耗性能。

反例:

image-20240925010133931

在循环中逐条插入数据。

image-20240925010145999

​ 该操作需要多次请求数据库,才能完成这批数据的插入。

​ 但众所周知,我们在代码中,每次远程请求数据库,是会消耗一定性能的。而如果我们的代码需要请求多次数据库,才能完成本次业务功能,势必会消耗更多的性能。那么如何优化呢?

正例:

image-20240925010216349

提供一个批量插入数据的方法。

image-20240925010230673

​ 这样只需要远程请求一次数据库,Sq性能会得到提升,数据量越多,提升越大。但需要注意的是,不建议一次批量操作太多的数据,如果数据太多数据库响应也会很慢。批量操作需要把握一个度,建议每批数据尽量控制在500以内。如果数据多于500,则分多批次处理。

3.6使用limit

​ 提高查询效率:一个查询返回成千上万的数据行,不仅占用了大量的系统资源,也会占用更多的网络带宽,影响查询效率。使用LIMIT可以限制返回的数据行数,减轻了系统负担,提高了查询效率。

​ 避免过度提取数据:对于大型数据库系统,从数据库中提取大量的数据可能会导致系统崩溃。使用LIMIT可以限制提取的数据量,避免过度提取数据,保护系统不受影响。

​ 优化分页查询:分页查询需要查询所有的数据才能进行分页处理,这会浪费大量的系统资源和时间。使用LIMIT优化分页查询可以只查询需要的数据行,缩短查询时间,减少资源的浪费。

​ 简化查询结果:有时我们只需要一小部分数据来得出决策,而不是整个数据集。使用LIMIT可以使结果集更加精简和易于阅读和理解。
限制行数非常有用,因为它可以提高查询性能、减少处理需要的时间,并且只返回我们关心的列。

3.7用union all代替union

union all:获取所有数据但是数据不去重,包含重复数据;

union:获取所有数据且数据去重,不包含重复数据。

​ 那么union allunion如果当然它业务数据容许出现重复的记录,我们更推荐使用union all,因为union去重数据需要遍历、排序和比较,它更耗时,更消耗CPU资源,但是数据结果最完整。

3.8join的表不宜过多

​ 查间效率下降:多表JOIN查间数据对比时间边长

​ 系统负载增加:JOIN操作需要进行大量的计算,因此会导致系统负载增加

​ 维护难度加大:在一个连接了多个表的查间中,如果需要修改其中一个表的结构或内容,就可能会需要同时修改其他表的结构或内容。因此,在数据库设计时,应该尽量减少JOIN操作的使用频率,并且简化表之间的关系,以提高查询效率和系统的性能。

除上述优化之外,通常在建表还需要注意以下内容:

​ 控制索引数量

​ 选择合理的字段类型

3.9总结

SQL优化是提高数据库性能的重要方法,在实际开发中我们的SQL要尽量遵守以下几点原则,避免留下技术债:

1.减少数据扫描

2.返回更少数据

3.减少交互次数

4.减少服务器CPU及内存开销

4.索引优化

示例:

image-20240925010759485

4.1全值匹配

MySQL全值匹配是指在使用复合索引时,查询条件要包含索引的所有列,才能最大程度地利用索引。

image-20240925011050128

查看索引长度是74=(3*24+2),可以算出联合索引中只使用了name前缀索引。

image-20240925011120885

image-20240925011134516

查看索引长度是78=(3*24+2)+4,可以算出联合索引中只使用了nameage前缀索引

image-20240925011200245

image-20240925011205957

查看索引长度是140=(3*24+2)+4+(3*20+2),可以算出联合索引中只使用了完整的联合索引

image-20240925011223633

4.2最左前缀法则

如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。

一一带头大哥不能死,中间兄弟不能断:

image-20240925011251076

4.3不在索引列上做操作

计算、函数、(自动o手动)类型转换,会导致索引失效而转向全表扫描

4.4存储引擎不能使用索引中范围条件右边的类

​ 范围查间会使后面字段无序,造成部分索引失效——范围之后全失效

image-20240925012021323

4.5尽量使用覆盖索引

​ 只访问索引的查询(索引列包含查询列),减少select*语句——覆盖索引不写星;

image-20240925011952150

4.6不等、空值、NULL导致索引失效

​ mysql 在使用不等于 (!=或者<>),not innot exists的时候无法使用索引会导致全表扫描。

​ <小于、>大于、<=、>=这些,mysql 内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引

image-20240925011739388

is null、is not null一般情况下也无法使用索引

image-20240925011808243

​ 少用orin,用它查询时,mysql 不一定使用索引,mysql 内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引,详见范围查询优化

image-20240925011848414

4.7LIKE模糊查询

百分查询模糊条件放在最右(第一个都不确定不如给你全扫描)

image-20240925011508141

问题:解决like%字符串%索引不被使用的方法?

​ a-> 使用覆盖索引,查询字段必须是建立覆盖索引字段

image-20240925011608067

​ b-> 如果不能使用覆盖索引则可能需要借助搜索引擎

4.8字符串不加单引号索引失效

​ 触发了类型转换

image-20240925011418971

4.9范围查询优化

给年龄添加单值索引

image-20240925012111118

没走索引原因:mysql 内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引。比如这个例子,可能是由于单次数据量查询过大导致优化器最终选择不走索引

优化方法:可以将大的范围拆分成多个小范围

image-20240925012144672

还原最初索引状态

image-20240925012158896

10.总结

全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断:
索引列上少计算,范围之后全失效:
Like百分写最右,覆盖索引不写星;
不等空值还有「,索引失效要少用:
VAR引号不可丢,SQL高级也不难!

第三章 面试题(补充中)

面试题1:

B树和B+树的区别,MySQL为什么要选择B+树作为默认的数据结构

image-20240924004155975

B+tree结构实现数据索引具有如下优点:

a.非叶子节点上可以存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树也就会变得更矮更胖。这样一来我们查找数据进行磁盘I/O的次数就会大大减少,数据查询的效率也会更快。

b.所有数据记录都有序存储在叶子节点上,就会使得范围查找,排序查找,分组查找以及去重查找变得异常简单。

C.数据页之间、数据记录之间都是通过链表链接的,有了这个结构的支持就可以方便的在数据查询后进行升序或者降序操作。

面试题2:

如果一个表没有主键索那还会创建B+树吗?

答案是会的!!!

​ InnoDB是MySQL中的一种存储引擎,它会为每个表创建一个主键索引。如果表没有明确的主键索引,InnoDB会使用一个隐藏的、自动生成的主键来创建索引。这个隐藏的主键索引使用的就是B+树结构。因此,在InnoDB中,即使表没有明确的主键索引l,也会创建一个B+树索引。

面试题3:

Hash索引优缺点

​ hash索引只能用于等值比较所以查询效率非常高

​ 不支持范围查询,也不支持排序,因为索引列的分布是无序的

面试题4:

单列索引联合索引分别什么场景创建,优势是什么

联合索引的优势

​ 1.减少开销:建一个联合索引(a,b,c),实际相当于建了(a)、(a,b)、(a,b,c) 三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销对于大量数据的表,使用联合索引会大大的减少开销。

​ 2.覆盖索引:对联合索引(a,b,c),如果有如下sql的select a,b,c from table where a='xxx'and b='xx',那么 mysql 可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机 io 操作。减少 io 操作,特别是随机 io 其实是 DBA 主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段。

​ 3.效率高:索引列多,通过联合索引筛选出的数据越少。

​ 比如有1000w条数据的表,有如下sql:select col1,col2,col3 from table where col1=1 and col2=2 and col3=3;假设每个条件可以筛选出10%的数据

​ A:如果只有单列索引,那么通过该索引能筛选出1000w*10%=100w条数据,然后再回表从100w条数据中找到符合col2=2 and col33=3的数据,然后再排序,再分页,以此类推(递归);

​ B:如果是(col1,Col2,col3)联合索引,通过三列索引筛选出1000w*10%*10%*10%=1w,效率提升可想。

面试题5:

索引的优缺点,什么时候该用和不该用

优点:

1.提高检索效率

2.降低排序成本,索引对应的字段是会有一个自动排序功能的,默认是升序 asc。

它缺点是 :

1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

2,索引需要占用物理空间,数据量越大,占用空间越大

3,会降低表的增删改的效率,因为每次增删改索引,都需要进行动态维护

面试题6:

竟然索引有坏有好,什么时候需要索引,什么时候不需要?

适合:

1.较频繁的作为查询条件的字段应该创建索引

不适合:

1.字段值的唯一性太差不适合单独做索引

2.更新非常频繁的字段不适合

3.不会出现在where句中的字段不适合。

徐庶—MySQL调优实践最全!必懂!知识点一站式掌握 (yuque.com)

pwd:nfyq

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/803155.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

924 pwn学习

9/24 pwn学习 知道了一次完整的pwn攻击流程,现在我们正式开始学习pwn基础知识 —————————pwn方向以 难入门 难提升著称 基础知识-C语言学习-1 由于pwn要求c语言必须掌握,所以我们先进行一段时间的的C语言学习 学习视频:浙江大学翁恺教你C语言程序设计!C语言基础入门…

Raft总结

Raft算法State所有server都有的持久化状态 先存储,然后响应RPCcurrentTerm 当前任期,初始为0,单调递增votedFor 当前任期投票给谁了,没有就是nulllog[] 日志条目,每个条目都包含命令、Leader收到条目时的任期,第一个条目的index为1所有server都有的Volatile statecommitI…

Lab3 Raft

Lab3 Raft 1.Getting Started 代码位置:基础框架代码位置:src/raft/raft.go测试代码:src/raft/test_test.go建议测试时使用-race 2.The code向raft/raft.go添加代码来实现Raft。实现必须支持以下接口 // 创建一个Raft Server rf := Make(peers, me, persister, applyCh) fun…

Lab3 记录

Part 3A: leader election 1.选举主要流程新服务器加入集群服务器在启动时状态是Follower。只要持续接收到Leader或Candidate的心跳信息,就继续保持Follower状态。开始选举每个Server都有一个随机的选举超时时间,选举超时在一个固定区间内随机选择(例如,150-300毫秒) 如果…

软件工程课程第三次作业

软件工程 https://edu.cnblogs.com/campus/fzu/SE2024作业要求 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13261作业目标 分析学生们的需求,设计一个app原型解决他们的问题学号 072208130合作伙伴 052205144张诗悦使用figma设计原型,原型链接:https://www.figma.…

大文件去重

若文件存的字符如下图,要求进行去重可将数据存入HashSet,如下,但如果文件很大,大于虚拟机内存的话,会报异常java.lang.OutOfMemoryError: Java heap spaceHashSet set = new HashSet();File file = new File("E:\\aa.txt");BufferedReader reader = new Buffere…

9月13日关于数组存储数据

在题目中要求建立数组来存储项目信息,储存的内容包括String、int、boolean、double等各种不同类型,刚开始我还处于建立普通数组要不是int【】要不是string【】,越琢磨越不对劲这样并不能存储不同类型的数据,但是数据又需要统一存取,网上又没有这么简单的讲解,也是被这个简…

9.24日总结

今日上学配置了Node.JS的环境变量,并应用VScode进行JavaScript的相关学习应用 其中

9月11日toString重载方法的使用

在编辑过程中我经常会写一部分调试一部分,至少知道哪里有错能够及时改正,在编写时发现studentManger中的打印出来的是地址,而不是自己想要的内容,经过查询是需要写toString来重载输出利用这样的方法,一是可以正常打印出自己想要的内容,而是可以根据一个参数打印出所有的信…

软件工程作业——结对项目

这个作业属于哪个课程 22级计科12班这个作业要求在哪 作业要求这个作业的目标 实现一个自动生成小学四则运算题目的命令行程序成员姓名 学号 GitHub地址吕宏鸿 3122004446 结对项目宋观瑞 3122004402 结对项目1.PSP表格PSP2.1 预估耗时(分钟) 实际耗时(分钟)计划 10 5* 估计…

9月10日循环条件的结束

在测试编程中涉及到输入错误要重新返回UI界面,但是我写的总是输入不管是对还是错都会直接结束程序,完全不符合要求,经过整理思路,查询代码结构,此处应该设计为双层循环外部为while,内部为witch case语句,当输入为1时执行case==1;经应该是执行生产计划类然后跳出witch条…

IDEA更改远程git仓库地址

前言 我们在使用IDEA开发时,一般会配置好对应的git仓库,这样就比较容易对代码进行控制以及协同开发。但有时候,我们远程的仓库地址由于这样那样的原因,需要迁移(这在爱折腾的企业是常有的事情)。那么,我们该如何在IDEA中更新远程仓库地址呢? 如何设置 首先,我们点击上…