Java开发 - 数据库索引的数据结构

简介: Java开发 - 数据库索引的数据结构

目录


前言

题外话

什么是索引

索引的使用场景

索引的失效瞬间

索引的数据结构

Tree

BTree

B+Tree

索引提高查询效率的原因

索引的分类

innodb的特点

聚簇索引

非聚簇索引

索引操作

创建索引

查询索引

删除索引

外键

结语


前言


上一章中讲解了慢sql优化的方式,其中索引并没有着重去说,那是因为索引内容特殊,它的数据结构复杂,足够我们单独开一篇来着重讲讲,这一篇将带领大家补齐上一章中关于索引优化的部分,也将对索引的底层数据结构做一个深度的剖析,希望大家喜欢。


题外话


之所以拖了这么久才开更是因为前几天🐑了,躲得过初一,躲不过十五,到今天才多少缓过来点劲,又重感冒加身,这哪是普通的发烧?简直是脱层皮啊。实际上我只烧了一天两夜,也就第一天不太起得来,第二天之后就是虚弱,时刻都能睡着,嗓子不怎么痛,就是咳嗽,到今天已经好很多了,一直出虚汗导致着凉又重感冒,999伺候吧。大家还是要照顾好自己。


什么是索引


索引是作用在数据库表的列上,用于对该列的数据进行排序,形成一个目录,从而提高查询效率的东西,索引比较适合数据量比较大的表中。


索引的使用场景


大数据量使用,因为索引的创建也需要一定的时间;

给需要作为查询条件的字段设置索引;

给不需要频繁修改的字段设置索引,若是经常修改,会导致索引重建,也会浪费时间;

索引不是越多越好,一般我们建议最多也就五六个吧。


索引的失效瞬间


索引的存在是为了帮助我们快速查询到数据,如果由于操作不当导致了全表扫描,那么索引就失去了其作用。接上一篇,所以我们使用sql的时候要避免这么做:


避免在where子句中对数据进行判null操作,这将导致引擎放弃使用索引而转而使用全表扫描,比如:where name is null 或者is not null;

避免在where子句中使用!=操作;

避免在where子句中使用or作为连接条件,比如where name=xxx or age=xxx,这会导致如果其中一个字段没有索引,其他有索引的字段也不会使用索引;

谨慎使用not in,in不会导致索引失效,not in(xxx,xxx,xxx,......)因为范围太大,索引就会失效,进行全表扫描;

避免在where子句当中使用like模糊查询,这里仅限左模糊(like '_%');

避免在where子句中使用表达式,比如:select ...... from table where age+4>20;

避免在where子句中使用函数表达式,比如:select ...... from ...... where round(money)=....

索引可以提高select的效率,但也会拉低insert和update的效率,因为insert和update可能导致索引重建。


索引的数据结构


索引的底层采用的是B+Tree


B+Tree又是基于BTree的


Tree


Tree就是树,顾名思义,像树一样的结构,只要是树,就一定拥有四个属性:


根结点:位于顶端且仅有一个

高度:整个树的层次

度:树中最大子节点数

叶子结点:位于最底层且没有子节点,或者说度为0的节点


BTree


我不能告诉你什么是BTree,因为其本质上就是一个Tree,BTree有如下特点:


以数据块来保存元素,并实现排序;

每个数据块中保存的最大数据量为(度-1),如果数据量达到度值,进行分裂提取,将中间值进行提取,原数据块分裂为左右两个数据块;

每次比较可通过中间值排除相当一部分的数据,树有几层,则排除几次,查询效率大大提高。

我们可以通过下图来查看BTree的数据结构大概长什么样:

1.png

指的注意的是,提取时,被提取的元素是中间值,且不会再存在于原数据块中(和B+Tree有区别),这些关键点要牢记。


B+Tree


和BTree相比,B+Tree的查询效率要更高,我们不妨来看看B+Tree和BTree有哪些不同吧:


叶子数据块之间通过单向链表进行连接,目的是为了提高区域查询效率(举个例子,比如查询相近的数据,比如查询0007和0011,查到0007之后,可以直接通过链表查询到下一个叶子结点找到0011,比重新中根结点开始查0011的效率要更高);


叶子数据块进行分裂提取的时候,被提取的数据依然位于叶子数据块中,但如果是非叶子数据块,则向上提取时不会继续保留到原数据块中,这是因为所有的数据都已经存在于叶子数据块中,非叶子数据块这时候只是起到了目录的作用,保证要查询的数据位于叶子结点中,这一点和BTree不太一样,BTree不一定查询到叶子结点。


查询次数减少,B+Tree我只关心叶子结点的数据,其他结点都只作为目录使用。


来看看B+Tree的数据结构:

1.png

和BTree很相似,但是其叶子结点间互相通过单向链表进行连接, 原因上面已经给出,可以看到,被从叶子提取出去的元素依然位于原模块中,非叶子结点则不会,这些被提取出去的节点就成了目录的效果,最终查询一定会到叶子结点。


索引提高查询效率的原因


数据库的索引都是保存在磁盘中的,且默认高度为3,度根据数据的量进行调整。所以查询的过程是IO查询。


当给数据库中某列添加一个索引的时候,索引就会对该列的数据进行排序,创建B+Tree目录,查询时根据该列进行查询时会通过B+Tree进行查询。


因为树的默认高度为3,所以最终都会进行3次的IO查询,第一次对根结点,第二次对子节点,第三次对叶子结点。这里要注意一点,每一次查询完都会将查到的数据缓存内存中进行多次的IO操作,这是因为在内存中查询效率更高,而每一个结点存在的数据不止一条。第三次缓存后在内存中查找具体的数据将最终得到想要的值。


注意:在内存中进行查询时采用的是二分查找法,而不是遍历。


虽然索引的底层是B+Tree,但是索引对B+Tree进行了优化:在叶子数据块中保存的元素不是一个元素值,而是以key-value的形式存在。至于key和value分别保存什么,要看索引的分类。


索引的分类


聚簇索引/聚集索引:给主键id添加的索引

非聚簇索引/非聚集索引:给非主键字短添加的索引

在说这两个索引之前,需要先讲一下innodb的特点,方便理解。


innodb的特点


我们知道,从mysql5.5开始,引擎被替换成了innodb:


innodb支持事务和行锁,上一篇有提到行锁;

默认给主键添加聚簇索引,如果没有设置主键,会自动添加隐藏主键,类行为long,长度为6,并添加聚簇索引;

除聚簇索引,innodb默认会给添加了unique约束以及外键约束的字段添加索引。


聚簇索引


聚簇索引由innodb默认添加,不需要开发者手动添加,这一点我们已经很清晰了。


聚簇索引中key和value分别是什么?


key为主键id;

value为id对应的整行数据。

这也是为什么通过id可以快速查找到整行数据的原因。


非聚簇索引


非聚簇索引需要开发者手动添加。


非聚簇索引中key和value分别是什么?


key为那一列的值;

value为该行数据对应的id的值

所以,非聚簇索引是先通过key找到主键的id的值,再通过id的聚簇索引找到整行数据,以达到快速查找数据的目的。我们把这一过程叫做“回表操作”。


索引操作


创建索引

create index index_name on table_name(col)
案例: 给字段添加unique约束,验证是否Innodb默认给添加了索引
添加unique约束:
已有表:alter table table_name add xxx type unique;
创建表:create table table_name(id int primary key,name varchar(50) unique)
对主键进行操作,可以尝试下,看是否会报错,报错则说明默认添加了索引,自行尝试。


查询索引

show index from table


删除索引

drop index index_name on table


外键


前面提到了外键,外键产生的原因是:一张表中的非主键字段来源于其他表中的主键字段的值,这就叫外键,是外键,就可以添加外键约束。


外键约束需要手动添加,被添加了外键约束的字段有个特点:这个被作为外键的主键字段原表中的那条数据不可被删除。


结语


这些东西没什么捷径可言,全凭经验。所以有时候你会看到工作好几年的人还是会犯同样的错误,这并不可怕,多练习,多总结,你现在踩过的坑终将成为你未来路上的垫脚石。

目录
相关文章
|
2天前
|
XML Java 数据库连接
性能提升秘籍:如何高效使用Java连接池管理数据库连接
在Java应用中,数据库连接管理至关重要。随着访问量增加,频繁创建和关闭连接会影响性能。为此,Java连接池技术应运而生,如HikariCP。本文通过代码示例介绍如何引入HikariCP依赖、配置连接池参数及使用连接池高效管理数据库连接,提升系统性能。
15 5
|
4天前
|
存储 SQL API
探索后端开发:构建高效API与数据库交互
【10月更文挑战第36天】在数字化时代,后端开发是连接用户界面和数据存储的桥梁。本文深入探讨如何设计高效的API以及如何实现API与数据库之间的无缝交互,确保数据的一致性和高性能。我们将从基础概念出发,逐步深入到实战技巧,为读者提供一个清晰的后端开发路线图。
|
2天前
|
存储 缓存 NoSQL
2款使用.NET开发的数据库系统
2款使用.NET开发的数据库系统
|
3天前
|
数据库 索引
数据库索引
数据库索引 1、索引:建立在表一列或多列的辅助对象,目的是加快访问表的数据。 2、索引的优点: (1)、创建唯一性索引,可以确保数据的唯一性; (2)、大大加快数据检索速度; (3)、加速表与表之间的连接; (4)、在查询过程中,使用优化隐藏器,提高系统性能。 3、索引的缺点: (1)、创建和维护索引需要耗费时间,随数据量增加而增加; (2)、索引占用物理空间; (3)、对表的数据进行增删改时,索引需要动态维护,降低了数据的维护速度。
12 2
|
5天前
|
存储 SQL 数据库
深入浅出后端开发之数据库优化实战
【10月更文挑战第35天】在软件开发的世界里,数据库性能直接关系到应用的响应速度和用户体验。本文将带你了解如何通过合理的索引设计、查询优化以及恰当的数据存储策略来提升数据库性能。我们将一起探索这些技巧背后的原理,并通过实际案例感受优化带来的显著效果。
18 4
|
13天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
69 1
|
14天前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
16 1
|
7天前
|
存储 关系型数据库 数据库
Postgres数据库BRIN索引介绍
BRIN索引是PostgreSQL提供的一种高效、轻量级的索引类型,特别适用于大规模、顺序数据的范围查询。通过存储数据块的摘要信息,BRIN索引在降低存储和维护成本的同时,提供了良好的查询性能。然而,其适用场景有限,不适合随机数据分布或频繁更新的场景。在选择索引类型时,需根据数据特性和查询需求进行权衡。希望本文对你理解和使用PostgreSQL的BRIN索引有所帮助。
15 0
|
14天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
45 0
|
6天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
20 4