当前位置: 首页 > news >正文

【初识数据库】索引

文章目录

  • 一.索引的概念
  • 二.索引采用的数据结构
  • 四.索引分类
  • 五.使用索引
    • 5.1 自动创建
    • 5.2 手动创建
    • 5.3 索引失效问题
      • 5.3.1 单列索引
      • 5.3.2 复合索引
    • 5.4 explain关键字


`

一.索引的概念

索引在数据库中是一种特殊的数据结构,其能够加快查找的速度,从而提升检索效率;
索引会占据额外的存储空间,因此后续进行插入/删除/修改时,可能会产生额外的开销;
但实际上,索引仍然是利大于弊的,这是因为:

  1. 索引带来的空间开销对现在来说算不上主要问题
  2. 日常开发中,通常查询的频率是高于增删改频率的

二.索引采用的数据结构

索引采用的数据结构是根据数据结构查询效率决定的;

1.为什么不使用顺序表?
=>顺序表的特点在于支持随机访问,但只是按index进行查找的,而我们的查找是按照值进行查找的,因此顺序表查找的效率并不高;


2.为什么不采用二叉搜索树?
=>二叉搜索树查询的时间复杂度为O(n),当处于最坏的情况下,其基本等于链表,此时无法体现出高效率;


3.为什么不用AVL树?
=>AVL树虽然能实现查询O(logn)的时间复杂度,但当涉及增删改时,可能就需要调整树的结构,当数据量非常多时,这样的操作是非常危险的,因此不予考虑;


4.为什么不用哈希表?
=>哈希表虽然查询的时间复杂度为O(1),但其查询基本为"等值"查询,无法实现范围查询,因此其不适合作为数据库索引;


5.为什么不用红黑树?
=>红黑树在查询时可以做到log(n)的复杂度,同时也能维持一定程度的平衡;其插入/删除/修改也比AVL树更加高效,因此其相比AVL树更加的均衡。同时,由于搜索树是的中序遍历是有序的,因此其也可以满足范围查询。但当树中元素变多时,树高也会随之变高,高度变高,比较的次数也会增加;在数据库中,每多一次比较,就多一次读硬盘操作,因此,不予采用;

实际上,索引采用的数据结构为B+树

在谈B+树之前,必须先谈一谈B树;
image.png
B+树的前身是B树,其是一个N叉树,每个节点有N个子树,因此每个节点可以保存多个值
虽然在查询时也会进行多次比较,但因为许多的比较都是在同一个节点中进行的,即只需要读一次硬盘。
由于其每个节点会保存多个值,因此,如果元素个数相同,B树要比红黑树的高度低的多

image.png

B+树是基于B树改进的N叉搜索树;

  • 一个节点中如果有N个值,就能延伸出N个子树;因此,每个节点的最后一个值,就是当前这颗子树的最大值;
  • 父节点的值会在子节点中以最大值身份出现,因此,所有叶子节点构成了整个数据集合
  • 使用双向链表将所有叶子节点进行连接
  • 叶子节点存储涉及到的数据行,非叶子节点存储索引编号

因此,B+树相对于其他数据结构的优势:

  • N叉搜索树的树高更低,因此进行查询时,读磁盘的次数更少
  • 所有的数据最终都在叶子节点上,因此其查询的次数是固定的
  • 叶子节点作为链表,因此其非常适合范围查询(根据搜索树快速定位起点终点);
  • 非叶子节点只存储id,占空间较小,允许更多的内存缓存,减少读硬盘次数

补充:B树的数据不一定落在叶子节点,那么使用B树会不会更好?
=>实际上,B树可能确实比较快,但其并不稳定。快是优点,但稳定也是优点。

image.png

如上谈到的B+树的结构,是针对主键索引来说的;
对于非主键列,创建的索引虽然也是B+树,但其叶子节点存储的并不是数据行,而是主键id;
一个表可以有多个索引,即有多个B+树,但存储数据行的B+树只有一个

非主键列的查询过程:

  1. 根据该列拿到对应的主键id
  2. 根据主键id从主键索引中再找一遍
    =>查询了两次B+树,即便如此,也比直接遍历快的多,如上的过程叫做回表;

三层B+树能存放多少数据?
假设:
主键占8字节,下一页地址占6字节,共14B,则16KB的页可以存161024/14=1170条索引记录;
故三层B+树的索引记录为:1170
1170*16=21902400,即三层B+树就可以表示2100多万条记录

因此,对于较大的表,就需要根据表的大小来评估B+树的层数。

那么如何优化表的大小?

  • 数据的冷热分离:将一个表分成两个表,一个放冷数据,一个放热数据;在每次查询时通过日志来记录哪些是冷热数据,累积一段时间就可以依此划分表;
  • 分库分表:对表中的id进行hash切割(如id%3),同一个id放入同一张表;

四.索引分类

索引可以分成:

  • 主键索引:为定义为主键的列添加或者为添加的自增列(Row_id标识)添加;
  • 唯一索引:为定义唯一键的列添加
  • 普通索引:手动的为指定列进行添加,可以指定多列;
  • 聚集索引:又叫聚簇索引,主键索引;
  • 非聚簇索引:聚集索引以外的索引,也叫二级索引;

五.使用索引

5.1 自动创建

当一张表给列添加了 主键/唯一键/外键时,会自动为对应列添加索引;

class(class_id,name);student(id,name,class_id)=>如上,会自动为class_id创建索引;

当添加外键索引时,子表进行插入/修改时,会查父表;父表中删除/修改时,也会查子表;

5.2 手动创建

-- 1.建表时创建索引
create table student(id int primary key,name varchar(10),index(name)/index(name,..)(复合索引)
);-- 2.建表后修改索引
alter table student add index(name);

创建索引可能是非常危险的
如果为一张很大的表创建索引,创建索引就要构建B+树,而这就意味着大量硬盘IO,开销会很大,严重的情况下可能干崩服务器;因此,最好能在建表的时候就创建好索引;

如果需求变更了,如何给正在运行中的mysql服务器大表创建索引?
image.png
如上,找另一台机器,搭建出和旧机器一样的mysql环境并创建符合索引要求的空表,将旧的服务器数据拷贝到新的服务器上,之后更改应用程序配置即可完成要求(其他相关操作也可考虑这种做法);

5.3 索引失效问题

索引能够加快数据的查询速度,但并非所有查询都能用索引加快搜索;
当发生索引失效时,会通过遍历的方式进行查询;
基本判断规则为:

  • 如果能确定在数据树中的方向,一层一层的进行查询,那么就索引命中;
  • 如果不能确定数据在树中的方向,一层一层的进行查询,那么就索引失效;

5.3.1 单列索引

假设有表: student(id,name,class_id),其中,id为主键索引,name为普通索引;

1.查询操作未使用索引列;

select * from student where class_id=xxx;    

2.索引列的值比较单一,则无法发挥效果;

select * from student where sex='男'; 
-- sex的值只要男/女,因此可以认为表中一半都是男生,无法根据值选出某一行/几行;

3.查询时,查询条件对索引列进行了表达式计算;

select * from student where id+10<50; 
-- 简单表达式还好,但如果是复杂的表达式甚至是函数,则每次比较均为进行调用,显然这是不合理的,因此mysql处理索引列表达式时,索引会失效

4.查询条件包含了or, or的一边是索引列条件,另一边是非索引列条件;

select * from student where id<50 or class_id>1; 

5.字符串查询涉及到like且通配符在首位置;

select * from student where name like '%鑫'/'_鑫';   
-- 通配符不在首位置,索引就可以正常生效;

6.查询索引列,但查询条件是 不等于或者not;

select * from student where id!=3;
-- =,<,>,<=,>=,均可以;   

7.多表联合查询,但表的字符集不一致时,也会导致索引失效;

utf-8 和 utf8mb4 可能会发生索引失效;  

5.3.2 复合索引

假设表的属性列: a,b,c,d,e,f, 其中假设(a,b,c)作为复合索引;
则:先根据a创建索引,如果记录的a值相同,则按照b创建索引,如果a,b值均同,则通过c创建索引;
当查询条件的索引列不符合最左前缀原则就会索引失效;
(a),(a,b),(a,b,c) =>索引命中
(b),(b,c),© =>索引未命中
(a,c) =>索引部分命中,但还可以接受;

5.4 explain关键字

mysql提供explain关键字来对索引进行分析,比如判断索引是否有效;

-- 语法: explain sql语句;
explain select * from student;
explain select * from where id<3;

image.png

http://www.dtcms.com/a/507369.html

相关文章:

  • Linux服务器编程实践59-管道通信:pipe函数创建匿名管道的方法与使用
  • 容器化安装新玩法
  • JVM内存分配机制
  • 企业网站的基本内容有哪些首页排名关键词优化
  • Qt C++ 调用 YOLO / SAM2的方案
  • AD导出FPGA管脚的方法
  • 邯郸做网站的公司郴州建设网站公司
  • 基于 ComfyUI + Wan2.2 animate实现 AI 视频人物换衣:完整工作流解析与资源整合(附一键包)
  • wdaaw
  • 做个企业网网站怎么做西安注册公司虚拟地址
  • [Java数据结构与算法]详解排序算法
  • 工业级时序数据库选型指南:技术架构与场景化实践
  • 精选五款电脑USB接口控制软件,助您高效管控USB端口
  • 有个性的个人网站js打开网站
  • tesla 2025 年在自动驾驶投入 多少钱
  • 做调查报告的网站钟点工
  • 在 Vue 3.5 中优雅地集成 wangEditor,并定制“AI 工具”下拉菜单(总结/润色/翻译)
  • 【YOLO模型】(4)--YOLO V3超超超超详解
  • idea 的全局的配置的修改
  • 永久免费云服务器推荐电子商务网站优化方案
  • Altium Designer(AD24)IEEE Symbols按钮总结
  • 阿里云k8s1.33部署yaml和dockerfile配置文件
  • 有口碑的盐城网站建设wordpress配置ip访问
  • LINUX15--进程间的通信-信号量
  • 在 Linux 内核中加载驱动程序(一)
  • yarn面试题
  • Android跨进程通信: Binder 进程间通信机制解析
  • 【Day 80】Linux-虚拟化
  • 建设厅官方网站网站主题的分类
  • 广州营销网站建设公司php网站开发实例项目