八股知识—数据库(二)索引

一、索引的概念

索引是一种数据结构。数据库索引是DBMS中一个排序的数据结构(有序),以协助快速查询、更新数据表中数据。索引的使用通常使用B树以及变种B+树。
索引就相当于目录,可以方便数据内容查找,本身也占用物理空间。

二、索引的优缺点

1. 索引的优点

①通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
②提高数据检索效率,降低数据库的IO成本,可以加快数据的检索速度。
③可以加速表和表之间的连接,特别是在实现数据的参考完整性方面。
④通过使用索引,可以在查询过程中,使用优化隐藏器,提高系统性能。
⑤通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。

2. 索引的缺点

①耗费时间,降低维护效率。创建和维护索引都要耗费时间,时间随着数据量的增加而增加。当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样降低了数据的维护速度。
②占用物理空间。空间是,索引需要占用物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。

三、索引的数据结构

(一)索引分类

1. 分类

数据库索引根据结构分类,主要有B+树索引、Hash索引、位图索引三种。

2. 不同存储引擎对应的索引结构

MYSQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构。

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

3.不同存储引擎对索引结构的支持

我们平常所说的索引,如果没有特别指明,都是指B+树结构组织的索引。

索引InnoDBMyISAMMemory
B+树索引支持支持支持
Hash索引不支持不支持不支持
R-Tree索引不支持支持不支持
Full-text5.6版本后支持支持不支持

(二)二叉树索引(未选择,本部分只是说明为什么MySQL不选择二叉树做索引)

1.二叉树索引理想结构

在这里插入图片描述

2.顺序插入

如果主键是顺序插入的,则会形成一个单向链表
在这里插入图片描述

3.二叉树索引缺点

①顺序插入时,会形成一个链表,查询性能大大降低。
②大数据量情况下,层级较深,检索速度慢。

4.解决方案

选择红黑树,红黑树是一颗自平衡二叉树,即使是顺序插入数据,最终会得到一颗平衡的二叉树。
在这里插入图片描述
解决了顺序插入的问题,但是红黑树也是二叉树,仍然存在大数据量情况下层级深检索慢的问题。【这也是MySQL的索引结构中不选择二叉树或红黑树的原因。】

(三)B-Tree索引

1.B树定义

B树是一种多叉路衡查找树,相对于二叉树,B树每个节点可以有多个分支,即多叉。

2.B树特点

一颗B树的最大度数是5(5阶B树),树的度数指的是一个节点的子结点个数。那这个B树每个节点最多可以存储4个key,5个指针。
在这里插入图片描述
即n阶B树,每个节点最多可以存储(n-1)个key,n个指针。在B树中,非叶子节点和叶子节点都会存放数据。

可以去这个网站动态演示一下B树的分裂过程

(四)B+Tree索引

1.B+树定义

B+树是B树的变种。假设一颗3阶B+树,则B+树每个节点存放2个key,3个指针。

绿色框部分是索引部分,仅仅起到索引数据的作用,不存储数据。
红色框部分是数据存储部分,在其叶子节点中要存储具体的数据。

2.B+树的特点

①所有的数据都会出现在叶子节点。
②叶子节点形成一个单向链表。
③非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。

可以去这个网站动态演示一下B+树的分裂过程

3.MySQL优化B+树索引

MySQL索引数据结构对经典的B+树进行了优化。在原B+树基础上,增加了一个指向相邻叶子结点的链表指针,形成了带有顺序指针的B+树,提高区间访问的性能,利于排序。叶子节点形成了双向链表。
在这里插入图片描述

4.B+树和B树的区别

B+树B树
①所有的非叶子节点只存储关键字信息,用做索引①所有的非叶子节点存储存储数据
②所有的具体数据存储在叶子节点中②所有的具体数据存放在全部节点中(叶子节点+非叶子节点)
③叶子节点包含了全部元素③叶子节点并不包含全部元素
④叶子节点之间有链指针④叶子节点之间没有链指针

(五)Hash索引

1.哈希索引定义

哈希索引就是采用一定的Hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。
在这里插入图片描述
如果两个(或多个)键值,映射到一个相同的槽位上,就产生了Hash冲突(hash碰撞),通过链表来解决。

2.哈希索引特点

①Hash索引只能用于对等比较\等值匹配(=,in),不支持范围查询(betweeen,<,>)。hash索引等值匹配的时候,只需要去计算对应hash值,然后去链表找到对应hash值即可。Hash索引存储的时候是没有顺序的,所以没有办法进行范围查询。
②无法利用索引完成排序操作,因为Hash计算得到的结果是无序的。
③查询效率高,通常只需要一次检索就可以了,效率通常要高于B+树索引。(前提是不出现Hash碰撞,出现了还要去链表中检索)

3.存储引擎支持

在MySQL中,支持Hash索引的是Memory存储引擎,而InnoDB中具有自适应Hash功能【指MySQL会根据查询条件,在指定的条件下,会自动地将B+树索引构建为Hash索引】,hash索引是InnoDB存储引擎根据B+树索引在指定条件下自动构建的。

为什么InnoDB存储引擎选择使用B+树索引结构?
①相对于二叉树,层级更少,搜索效率更高。
②对于B树,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页(一页大小固定为16K)中存储的键值减少、指针跟着减少,要同样保存大量数据,只能增加树的高度,层级变多,查询性能降低。而B+树的非叶子节点存放键值和指针,不存放数据,同样保存大量数据,数据可放的位置变多,树的高度相对较低,层级少,查询性能高于B树。
③相对于Hash索引,B+树支持范围匹配以及排序。Hash索引支持精确查找,不支持范围匹配,也不支持排序。

四、使用B+树的好处

①相对于二叉树,层级更少,搜索效率更高。
②对于B树,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页(一页大小固定为16K)中存储的键值减少、指针跟着减少,要同样保存大量数据,只能增加树的高度,层级变多,查询性能降低。而B+树的非叶子节点存放键值和指针,不存放数据,同样保存大量数据,数据可放的位置变多,树的高度相对较低,层级少,查询性能高于B树。
B+树的非叶子节点只存放键,不存放数据,一次读取,可以在同一页中获取更多的键,有利于更快缩小查找范围。
③相对于Hash索引,B+树支持范围匹配以及排序。Hash索引支持精确查找,不支持范围匹配,也不支持排序。
④B+树的叶子节点有链相连,进行一次全数据遍历的适合,B+树只需要适应O(logN)时间找到最小节点,然后通过链进行O(N)的顺序遍历即可;在找大于某个关键字或者小于某个关键字的数据的时候,B+树只需要找到该关键字然后沿着链表遍历即可。

五、Hash索引和B+树索引的区别

Hash索引B+树索引
等值查询等快(通常下,没有Hash碰撞),不支持范围查询支持等值查询和范围查询
不支持使用索引排序支持使用索引排序
不支持模糊查询支持模糊查询
不支持多列索引的最左前缀匹配支持多列索引的最左前缀匹配
Hash索引避免不了回表查询B+树符合(聚簇索引、覆盖索引)时,可以只通过索引完成查询
性能不稳定(发生Hash碰撞,效率低)查询效率稳定,所有查询都是从根节点到叶子节点

六、索引的分类

(一)索引分类

在这里插入图片描述

(二)聚集索引&二级索引

1.InnoDB存储引擎中分类

在InnoDB存储引擎中,根据索引的存储形式,分为:
在这里插入图片描述

2.聚集索引选取规则

①如果存在主键,主键索引就是聚集索引。
②如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
③如果表没有主键,也没有合适的唯一索引,则InnoDB回自动生成一个rowid作为隐藏的聚集索引。
【无论如何,聚集索引一定存在,聚集索引只有一个】

3.聚集索引和二级索引具体结构

在这里插入图片描述

聚集索引的叶子节点下挂的是这一行的数据,也就是name+gender。
二级索引的叶子节点下挂的是该字段值对应的主键值。例如姓名为ARM,该叶子节点下挂的是对应ID10,也就是主键值。

4.回表查询

回表查询指的是先到二级索引中查找数据,找到主键值,然后到聚集索引中根据主键值,获取对应数据的方式。

在这里插入图片描述
解答:A语句的执行效率高于B语句。
A语句直接去聚集索引根据主键值ID查询即可,直接返回数据。B语句要去二级索引查找到名字ARM对应的主键值,然后返回到聚集索引去根据主键值ID去查找数据,需要进行回表查询。

InnoDB主键索引的B+树高度为多高呢?
解答:
①存储引擎中一页的大小为16K,即16×1024个字节。
②假设一行数据大小为1K,也就是叶子节点存放的数据,而一页是16K,那么一页可以存放16行这样的数据。
③假设InnoDB指针占用6个字节,主键Key(bigint)占用8个字节。
④假设树的高度为2。一页当中存放的指针(n)和主键Key(n-1)计算
n×6+(n-1)×8=16×1024,得到n为1171。有1171个指针,1170个Key。那么叶子节点存放的数据大小为,有1171个指针,每个指针指向存放数据的叶子节点对应页,一页可以存放16行数据,那么1171×16=18736行等于这个高度为2的树可以存放这么多行数据。
⑤假设树的高度为3呢,那么可以存放1171×1171×16=21939856行数据。

七、索引语法

(一)创建索引

CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (
index_col_name,... ) ;

UNIQUE代表创建的是一个唯一索引,要求该字段不能出现重复的数据。FULLTEXT代表创建的是全文索引。
(要为哪一张表中的哪个字段创建索引,table_name index_col_name)

一个索引是可以关联多个字段的,如果一个索引只关联一个字段,这个索引称为单列索引。
如果一个索引关联了多个字段,这个索引称为联合索引或组合索引。

(二)查看索引

SHOW INDEX FROM table_name ;

(三)删除索引

DROP INDEX index_name ON table_name ;

八、SQL性能优化

(一)SQL执行频率

1.相关指令

MySQL客户端连接成功后,通过show [session | global ] status命令可以提供服务器状态信息。

SHOW GLOBAL STATUS LIKE 'Com___';

GLOBAL是查看数据状态信息。
SESSION是查看当前会话状态信息。
Com_delete:删除次数
Com_insert:插入次数
Com_select:查询次数
Com_update:更新次数

2.作用

通过上述指令,可以查看当前数据库到底是以查询为主,还是以增删为主,如果以增删为主,我们就不考虑其优化,如果是查询为主,就要考虑对数据库的索引进行优化。

(二)慢查询日志

1.定义

慢查询日志记录了所有执行时间超过指定参数(Long_query_time,单位:秒,默认10秒)的所有SQL语句。【SQL语句执行时间超过10秒,就会被记录在慢查询日志当中】

2.语法

show variables like 'slow_query_log';
--MySQL的慢查询日志默认没有开启,查看系统变量
--如果要开启慢查询日志,需要在MySQL的配置文件中进行配置。
vi  /etc/my.cnf
--开启MySQL慢查询日志开关
slow_query_log=1;
--设置慢查询日志的时间为2秒,SQL语句执行时间超过2秒,被视为慢查询,记录到慢查询日志中
long_query_time=2;

(三)profile详情

1.profile操作

show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看到当前MySQL是否支持profile操作。

SELECT @@have_profiling ;
SELECT profiling;
--查看开关状态

可以通过set语句在session/global级别开启profiling

SET profiling = 1;

开关已经打开了,接下来,我们所执行的SQL语句,都会被MySQL记录,并记录执行时间消耗到哪儿去了。
执行一系列的业务SQL的操作,然后通过如下指令查看指令的执行耗时:

-- 查看每一条SQL的耗时基本情况
show profiles;
-- 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
-- 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;

(四)explain执行计划

1.定义及语法

EXPLAIN 或 DESC 命令获取MySQL是如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序。
语法:

--直接在select语句之前加上关键字 explain /desc
EXPLAIN +查询语句;

2.explain各字段含义

在这里插入图片描述
尽量将type往前优化,不要是all。

九、索引使用

(一)最左前缀匹配原则

1.定义

如果所有是联合索引(多列索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。
对于最左前缀法则指的是,查询时,最左变的列,否则索引全部失效,采用全局扫描。
最左前缀法则中指的最左边的列,是指在查询时,联合索引的最左边的字段(即是第一个字段)必须存在,与我们编写SQL时,条件编写的先后顺序无关。

(二)范围查询

1.定义

联合索引中,出现范围查询(>,<),范围查询右边的索引会失效。
在这里插入图片描述
在联合索引中,范围查询最好使用(>= , <=),这样就可以走联合索引,范围查询右侧的索引也不会失效,所有字段都是走索引的。

所以,在业务允许的情况下,尽可能的使用类似于 >= 或 <= 这类的范围查询,而避免使用 > 或 <

(三)索引失效情况

1.索引列运算

不要在索引列上进行运算操作,索引将失效。
在这里插入图片描述

2.字符串不加引号

字符串类型字段使用时,不加引号,索引将失效。字符串不加单引号,对于查询结果没有什么影响,但是数据库存在隐式类型转换,索引将失效。

3.模糊查询

如果仅仅是尾部模糊匹配(like ‘软件%'),索引不会失效。如果是头部模糊匹配(like ’%工程‘),索引失效。
在like模糊查询中,在关键字后面加%,索引可以生效。而如果在关键字前面加了%,索引将会失效。

4.or连接条件

用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。当or连接的条件,左右两侧字段都有索引时,索引才会生效。

5.数据分布影响

如果MySQL评估使用索引比扫描全表更慢,则不使用索引。
因为MySQL在查询时,会评估使用索引的效率与走全表扫描的效率,如果走全表扫描更快,则放弃索引,走全表扫描。 因为索引是用来索引少量数据的,如果通过索引查询返回大批量的数据,则还不如走全表扫描来的快,此时索引就会失效。(取决于表中数据的分布,查询对应的数据是极少部分,则走全表扫描。)

(四)SQL提示

1.定义

SQL提示是优化数据库的一个重要手段,在SQL语句中加入一些人为的提示来达到优化操作的目的。

2.use index

建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进行评估)。
在这里插入图片描述

3.ignore index

忽略指定的索引。
在这里插入图片描述

4.force index

强制使用指定的索引(MySQL不可以有自己的想法)。
在这里插入图片描述

(五)覆盖索引

1.定义

覆盖查询是指查询使用了索引,并且查询需要返回的列,在该索引中可以全部找到。(减少select *,改为具体的select id,name等)。
在这里插入图片描述

覆盖索引性能高一点,如果使用select * ,很容易出现回表查询的情况,性能低。
在这里插入图片描述
创建一个联合索引,满足覆盖索引,这样二级索引下挂的就是主键索引,可直接获得ID信息。

(六)前缀索引

1.定义

当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。

2.创建语法

create index idx_xxxx on table_name(column(n)) ;

前缀长度也就是n的值,可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高, 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

--计算选择性,选择性=1性能最好。
select count(distinct email) / count(*) from tb_user ;
--截取n个前缀
select count(distinct substring(email,1,n)) / count(*) from tb_user ;

3.查询流程

在这里插入图片描述

(七)单列索引与联合索引

1.定义

单列索引:一个索引只包含单个列。
联合索引:一个索引包含多个列。

2.单列索引及多列索引查询选择

在and连接查询的两个字段,各自有各自的单列索引,但是最终MySQL只会选择一个索引,只能走一个字段的索引,会进行回表查询。那么此时最好使用联合索引,无需回表查询。推荐使用联合索引!

八、添加索引的原则

  1. 针对于数据量较大,且查询比较频繁的表建立索引。
  2. 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
  3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  4. 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
  5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
  6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
  7. 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

请添加图片描述

### 数据库面试常见问题与八股知识点 #### 1. 数据库锁机制及其分类 数据库锁是为了控制并发访问的一种机制,防止多个事务同时修改同一份数据而导致不一致的情况发生。根据锁的范围大小,可以分为以下几种粒度[^2]: - **表级锁**:锁定整个表,适用于批量操作场景,但并发性能较差。 - **行级锁**:仅锁定特定的行,适合高并发环境下的精确控制,但开销较大。 - **页级锁**:介于表级锁和行级锁之间,锁定的是页面级别的数据。 全局锁的应用可能会导致严重的业务停滞问题,因为它会使整个数据库处于只读状态,在备份过程中无法进行任何更新操作[^1]。 --- #### 2. ARIES 日志恢复方法的核心原理 ARIES 是一种高效的日志恢复技术,主要应用于关系型数据库中以保障一致性。它由三个阶段组成: - **分析阶段**:识别已提交、活跃以及中断的事务,为后续处理提供依据。 - **重做阶段**:通过重新执行 redo 操作,确保所有已完成的操作都被正确反映到数据库中。 - **撤销阶段**:回滚未完成的事务,清除残留的影响并保持数据完整性。 这种方法的优势在于高效且可靠,尤其对于大规模事务系统尤为重要。 --- #### 3. 数据库分片策略的选择 随着数据规模的增长,单机存储可能不再满足需求,此时可以通过分片来扩展容量。常见的分片方式有两种[^3]: - **客户端代理**:将分片逻辑嵌入应用程序内部,通常借助 JDBC 层实现(如 Sharding-JDBC)。这种方式减少了额外的服务依赖,但也增加了开发复杂度。 - **中间件代理**:引入独立的代理层负责路由请求至对应的物理节点(如 MyCAT 或 Atlas)。虽然简化了应用侧的设计,却带来了更多的运维负担。 需要注意的是,《Java 工程师修炼之道》建议尽量避免过早采用分片设计,除非确实面临海量数据的压力;否则简单的优化手段即可应对大多数中小规模场景的需求。 --- #### 4. MySQL 的索引结构详解 MySQL 支持多种类型的索引,其中 B+Tree 是最常用的形式之一。它的特点是叶子结点保存全部键值对,并按序排列形成链表连接起来,便于快速定位目标记录位置。此外还有哈希索引用于等值查询加速,全文索引针对文本检索场合等特殊用途。 创建复合索引时需注意字段顺序安排合理,遵循“左前缀原则”,即只有当左边部分匹配成功后才会继续查找右边剩余条件。 --- #### 5. 死锁检测与预防措施 死锁是指两个或更多事务互相等待对方释放资源的现象。为了避免这种情况的发生,可以从以下几个方面入手: - 设置超时时间限制; - 主动探测冲突情况并通过强制终止某个参与者打破循环依赖链条; - 推荐按照固定次序获取锁资源从而降低交叉干扰概率。 实际项目中应综合考虑效率损失与安全性之间的平衡点做出权衡决策。 --- ### 示例代码片段 下面展示如何利用 Python 连接 MySQL 并执行简单查询语句: ```python import mysql.connector def connect_to_mysql(): try: connection = mysql.connector.connect( host="localhost", user="root", password="password", database="testdb" ) cursor = connection.cursor() query = "SELECT * FROM users WHERE id=%s;" cursor.execute(query, (1,)) result = cursor.fetchall() for row in result: print(row) except Exception as e: print(f"Error occurred: {e}") finally: if 'connection' in locals() and connection.is_connected(): cursor.close() connection.close() connect_to_mysql() ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值